Categories
Vue 3

Form Validation in a Vue 3 App with Vee-Validate 4 — Cross-Field Validation and Array Validations

Spread the love

Form validation is an important part of any app.

In this article, we’ll look at how to use Vee-Validate 4 in our Vue 3 app for form validation.

Cross-Field Validation with defineRules

We can add cross-field validation without the Yup library.

To do this, we write:

<template>
  <div>
    <Form @submit="onSubmit">
      <div>
        <label for="password">Password</label>
        <Field name="password" type="password" rules="required|min:5" />
        <ErrorMessage name="password" />
      </div>

      <div>
        <label for="passwordConfirmation">Confirm Password </label>
        <Field
          name="passwordConfirmation"
          type="password"
          rules="required|confirmed:@password"
        />
        <ErrorMessage name="passwordConfirmation" />
      </div>
      <button type="submit">Submit</button>
    </Form>
  </div>
</template>

<script>
import { Field, Form, ErrorMessage, defineRule } from "vee-validate";

defineRule("required", (value) => {
  if (!value) {
    return "This is required";
  }
  return true;
});

defineRule("min", (value, [min]) => {
  if (value && value.length < min) {
    return `Should be at least ${min} characters`;
  }
  return true;
});

defineRule("confirmed", (value, [other]) => {
  if (value !== other) {
    return `Passwords do not match`;
  }
  return true;
});

export default {
  name: "App",
  components: {
    Field,
    Form,
    ErrorMessage,
  },
  methods: {
    onSubmit(values) {
      alert(JSON.stringify(values, null, 2));
    },
  },
};
</script>

We called defineRule to define the required rule to check if the field is filled in.

min checks if the field has a minimum amount of characters.

confirmed checks that the other field’s value matches the current field’s value.

value has the value of the field. And other has the value of the other field.

Array Fields

We can validate fields that are rendered from an array.

To do this, we write:

<template>
  <div>
    <Form @submit="onSubmit" :validation-schema="schema">
      <fieldset v-for="(user, idx) in users" :key="user.id">
        <legend>User {{ idx }}</legend>
        <label :for="`name_${idx}`">Name</label>
        <Field :id="`name_${idx}`" :name="`users[${idx}].name`" />
        <ErrorMessage :name="`users[${idx}].name`" as="p" />

        <label :for="`email_${idx}`">Email</label>
        <Field
          :id="`email_${idx}`"
          :name="`users[${idx}].email`"
          type="email"
        />
        <ErrorMessage :name="`users[${idx}].email`" as="p" />
        <button type="button" @click="remove(user)">X</button>
      </fieldset>

      <button type="button" @click="add">Add User +</button>
      <button type="submit">Submit</button>
    </Form>
  </div>
</template>

<script>
import { Field, Form, ErrorMessage } from "vee-validate";
import * as yup from "yup";

export default {
  name: "App",
  components: {
    Field,
    Form,
    ErrorMessage,
  },
  data: () => {
    const schema = yup.object().shape({
      users: yup
        .array()
        .of(
          yup.object().shape({
            name: yup.string().required().label("Name"),
            email: yup.string().email().required().label("Email"),
          })
        )
        .strict(),
    });

    return {
      schema,
      users: [
        {
          id: Date.now(),
        },
      ],
    };
  },
  methods: {
    onSubmit(values) {
      alert(JSON.stringify(values, null, 2));
    },
    add() {
      this.users.push({
        id: Date.now(),
      });
    },
    remove(item) {
      const index = this.users.indexOf(item);
      if (index === -1) {
        return;
      }

      this.users.splice(index, 1);
    },
  },
};
</script>

We create the schema object with Yup to call yup.array to let us validate array.

Then we call of to let us specify the validation schema for the objects inside.

The name attributes of each field should be a string that takes the form of an array path.

Now when we type in something invalid in any entry, we’ll see errors displayed.

Conclusion

We can do cross-field validation and array field validations in our Vue 3 app with Vee-Validate 4.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *