Vue.js Form Validation With Vuelidate - An Introduction
Vue.js
19/03/2019
Form Validation is one of those icky subjects that doesn't tickle my fancy and I'm quite certain many others feel the same way. While Vue.js enables you to implement form validation on your own, it can quickly become a hot mess the more fields and the more complex your validations become. But don't worry! Vuelidate is a great lightweight library that's going to make our task so much easier and more enjoyable. In this tutorial, I'll be giving you an introduction to Vue.js form validation with Vuelidate. So let's get started, shall we? 🤞
Installation
You can install Vuelidate in your project by running one of the following commands:
$ yarn add vuelidate
$ npm install vuelidate --save
After installing it via your package manager, you'll need to register the plugin in your main.js
file.
import Vue from 'vue';import Vuelidate from 'vuelidate';import App from 'App.vue';
Vue.use(Vuelidate);
new Vue({ el: '#app', render: h => h(App)});
Adding Validation
So how does Vuelidate work? Let's start with a simple example below.
<template> <form @submit.prevent="onSubmit"> <div> <label for="email">Email </label> <input type="text" id="email" v-model="emailField"> </div> <button type="submit">Submit</button> </form></template>
<script>export default { name: "HelloWorld", data() { return { emailField: "" }; }};</script>
Above we've got a simple form with a single field in which you can enter your email. Note the two-way binding with emailField
. Now, let's imagine we want the text input to be a valid email address as well as a requirement. How would we do this with Vuelidate?
Built-in Validators
Vuelidate has a number of built-in validators which we can easily implement into our form. However, to do so we will need to import these validators into our component. In particular, to complete our task we will want to import the validators required
and email
.
<script>// New codeimport { required, email } from 'vuelidate/lib/validators';
export default { name: "HelloWorld", data() { return { emailField: "" }; }, // New code validations: { emailField: { required, email, } }};</script>
Besides the import statement at the top of our script section, we've also added a validations
property. In this property, we pass in an object containing the data that we would like to validate. In our case, we want to validate emailField
. Next, we also pass in an object specifying the types of validators we would like, i.e. required
and email
.
Exposing $v
So far so good! However, this alone won't do anything. Rather, we need to make use of information on the validation state that is exposed to us through the Vuelidate property $v
. In fact, by inserting {{ $v }}
into your HTML you can see the entire object it returns, including its properties. Why not give it a try and see for yourself? Although, for the lazy ones of you... below you can see what it would look like anyways.
As you can see, the entire object contains information about the state of emailField
. Vuelidate has documented what all the $v
values mean. Likewise, Vuelidate also features $v
methods that you can make use of on events. These methods are built in and as such there's no need to import them.
Alright, let's move on!
First, let's add the $touch()
method to our input field as follows.
<input type="text" id="email" v-model="emailField" @input="$v.emailField.$touch()">
With this piece of code, we basically want to change the property $dirty
of our emailField
to true on any input. $dirty
basically indicates whether the field has been interacted with by the user at least once. You may be wondering why that's necessary, and you'll find out about it in the next section! 😜
Displaying errors
Let's insert two lines of text below our input field, each describing their respective error as seen below. Don't forget to colour them red! That makes them look more official. 🧐
<label for="email">Email </label><input type="text" id="email" v-model="emailField" @input="$v.emailField.$touch()">// New code<p class="error">An email is required!</p><p class="error">The email must be valid!</p>
Alright. How about controlling when they appear? For that we can use v-if
and our beloved $v
values. In particular, we want to access the required
and email
properties, which indicate true or false on the state of our validation.
<p class="error" v-if="!$v.emailField.required">...</p><p class="error" v-if="!$v.emailField.email">...</p>
Now, you may be tempted to call it a day. However, if you have been following this tutorial along on your own, you may have noticed that our required error displays even when our user hasn't entered anything. Well, this is where our handy dandy $dirty
value comes in. By simply adding it to the v-if
statement, we can get rid of this minor issue.
<p class="error" v-if="!$v.emailField.required && $v.emailField.$dirty">...</p>
Custom Validator
Sooner or later, you might need a validator that Vuelidate doesn't have. In such a case, you can resort to creating your own custom validator. Let's continue with our previous email example and create a uniqueness validator for it. For instance, you may assume we are validating the input against an existing list of emails in our database. 📑
// Not in methods property!let unique = (value) => value !== 'test@gmail.com';
// ...
validations: { emailField: { required, email, unique, }}
In our script section, we first create a unique
function that compares our input to the string 'test@gmail.com'
and returns true or false accordingly. Fortunately, custom validators automatically receive our input as a parameter, which I named here as value
. Afterwards, the only thing left is to add the function to the validations property under the emailField
property.
If you've still got $v
exposed in you HTML, you will see the addition of our unique
validator. All that's left now is to add an error message for the user. 🚨
<p class="error" v-if="!$v.emailField.unique">This email is already taken!</p>