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.