Categories
Vue

Vuelidate — Forms, Related Fields, and Nested Fields Validation

Spread the love

Vue.js doesn’t come with any form validation capabilities by default.

Therefore, we need to add our own form validation library or with our own code.

In this article, we’ll look at how to validate forms with Vuelidate.

Form Submission

We can check a form’s validity before submission with Vuelidate.

To do this, we can check the $invalid state before sending any requests.

For example, we can write:

<template>
  <div id="app">
    <form @submit.prevent="submit">
      <div :class="{ 'form-group--error': $v.name.$error }">
        <label>Name</label>
        <input v-model.trim="$v.name.$model">
        <div v-if="!$v.name.required">Field is required</div>
        <div
          v-if="!$v.name.minLength"
        >Name must have at least {{$v.name.$params.minLength.min}} letters.</div>
      </div>
      <div :class="{ 'error': $v.age.$error }">
        <label>Age</label>
        <input v-model.trim.lazy="$v.age.$model">
        <div
          class="error"
          v-if="!$v.age.between"
        >Must be between {{$v.age.$params.between.min}} and {{$v.age.$params.between.max}}</div>
      </div>
      <input type="submit" value="submit">
    </form>
  </div>
</template>
<script>
import { required, minLength, between } from "vuelidate/lib/validators";
export default {
  name: "App",
  data() {
    return {
      name: "",
      age: 0
    };
  },
  validations: {
    name: {
      required,
      minLength: minLength(4)
    },
    age: {
      between: between(20, 30)
    }
  },
  methods: {
    submit() {
      this.$v.$touch();
      if (this.$v.$invalid) {
        alert("error");
      } else {
        alert("submitted");
      }
    }
  }
};
</script>

We have the @submit.prevent directive to run the submit method when we click on the submit button.

In the submit method, we run this.$v.touch() to trigger form validation.

Then we check the this.$v.$invalid property to see if the form is invalid or not.

Contextified Validators

We can check related fields with contextified validators.

For example, we can write:

<template>
  <div id="app">
    <div>
      <div :class="{ 'form-group--error': $v.password.$error }">
        <label>Password</label>
        <input v-model.trim="$v.password.$model">
        <div class="error" v-if="!$v.password.required">Password is required.</div>
        <div
          class="error"
          v-if="!$v.password.minLength"
        >Password must have at least {{ $v.password.$params.minLength.min }} letters.</div>
      </div>

      <div :class="{ 'form-group--error': $v.repeatPassword.$error }">
        <label>Repeat password</label>
        <input v-model.trim="$v.repeatPassword.$model">
      </div>
      <div class="error" v-if="!$v.repeatPassword.sameAsPassword">Passwords must be identical.</div>
    </div>
  </div>
</template>
<script>
import { required, sameAs, minLength } from "vuelidate/lib/validators";
export default {
  name: "App",
  data() {
    return {
      password: "",
      repeatPassword: ""
    };
  },
  validations: {
    password: {
      required,
      minLength: minLength(6)
    },
    repeatPassword: {
      sameAsPassword: sameAs("password")
    }
  }
};
</script>

We added the sameAs validator to the repeatPassword field with the string of the field we want to compare with as the argument.

This way, we can make sure that both the password and repeatPassword fields are the same.

Data Nesting

We can validate nested data.

If a children validator has $invalid set to true , then the parent validator will also have $invalid true .

For example, we can write:

<template>
  <div id="app">
    <div>
      <div :class="{ 'form-group--error': $v.form.name.$error }">
        <label>name</label>
        <input v-model.trim="$v.form.name.$model">
        <div class="error" v-if="!$v.form.name.required">name is required.</div>
      </div>

      <div :class="{ 'form-group--error': $v.form.age.$error }">
        <label>age</label>
        <input v-model.trim="$v.form.age.$model">
      </div>
      <div class="error" v-if="!$v.form.age.required">age is required.</div>
    </div>
  </div>
</template>
<script>
import { required } from "vuelidate/lib/validators";
export default {
  name: "App",
  data() {
    return {
      form: {
        name: "",
        age: ""
      }
    };
  },
  validations: {
    form: {
      name: {
        required
      },
      age: {
        required
      }
    }
  }
};
</script>

We defined the nested fields in the object we return in data and in the validations object.

Then in the template, we just access the properties as we have them in the component code.

Conclusion

We can validate forms, related fields and nested fields with Vuelidate.

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 *