Following my previous article on Vue.js and editable contents, I continue my walkthrough with Vue.js, this time going into plugins section to validate my forms using Vue-validator.

Vue-validator will leverage two-way bindings of VueJS to check your form and display error messages or block user to perform an action.
Warning as usual with client-side validation of any kind, do not assume that if request has been submitted the data are in the correct format and can be freely processed. Never trust client data and perform the checks again on server side. Client-side validations are useful to provide an immediate feedback to the user prior to the first submission of data. A malicious HTTP/S call can always be built to avoid your client-side validation.

Loading the plugin

Ok, let's start now.
First, we need to include the extension and the easiest way to start testing is to include the CDN version of the file by adding:

<script src="https://cdn.jsdelivr.net/vue.validator/2.1.3/vue-validator.min.js"></script>

Then, we need to tell VueJS to use the plug-in:
<script>Vue.use(VueValidator)</script>

The plugin is now available for all components you'll instantiate later. ###Sample - create user form To illustrate plugin usage, let's take a form we all know: Creating a new user. We've all gone through the process of creating this form (yes, don't lie). In our form, we'll have 3 fields: user email, password and confirm password (nothing really fancy isn't it?). However, with only these fields, we'll have to check:
  • All fields are mandatory
  • Email format
  • If password is long enough
  • If both version of the provided password are the same
  • And possibly other checks like user does not exist or password format but I won't go through these ones here
So for that let's create our basic form:
<form>
    <p>
        <label>Username</label>
        <input type="email" name="email"/>
    </p>
    <p>
        <label>Password</label>
        <input type="password" name="password"/>
    </p>
    <p>
        <label>Confirm password</label>
        <input type="password" name="confirmPassword"/>
    </p>
    <p>
        <input type="submit" value="Create user"/>
    </p>
</form>

In order to use vue-validator plugin, the form needs to be surronded by a <validator> tag and with one more wrapper to call VueJS it becomes:

<div id="creationForm">
    <validator name="validator">
        <form>
            ...
        </form>
    </validator>
</div>

Now, to start validator, we only need to instanciate a VueJS component like usual:

<script>
    new Vue({
        el: "#creationForm"
    });
</script>

In this sample, I'll only focus on form validation but all other features of any VueJS component are available like data binding. We don't need it for validation as this markup created an internal attribute for the component named $validator ($ is added to avoid collision with object in data if provided).

Adding validations

Vue-validation comes with a set of built-in validations: required, minlength, maxlength, min, max and pattern.
To add a validation to a field, we need to add v-validate attribute to the input field. It is parametered with a fieldname to retrieve errors and with rules to apply:

<input v-validate:fieldName="{ setOfRules }"/>

To add required validation to the first field it becomes:

<input type="email" name="email" v-validate:email="{required: true}"/>

true is added to notify that it is mandatory. We could have used ['required'] syntax instead of previous one but this syntax limits the number of validators to one and we'll add one more later.
Still using built-in validators, we'll add a minimum length of 8 characters to password fields:

<input type="password" name="password" v-validate:password="{required: true, minlength: 8}"/>

For email format, we have two options, the first one is to use built-in pattern validator and provide the regexp to follow but I'll use custom validation instead to introduce it.
Vue-validator plugin allows you to define custom validators either at top level or at component level. As email validation format is pretty common, let's declare it at the global level:

Vue.validator('email', function (val) {
  return /^(([^<>()[]\.,;:\s@\"]+(.[^<>()[]\.,;:\s@\"]+)*)|(\".+\"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,}))$/.test(val)
})

First argument of Vue.validator is the name of the validator, here email. The second one is the function that'll be executed to perform check. It has to return a boolean: true if validation succeed, false if not (no kidding!). This function can take 1 or 2 parameters: the first one, val, will be the value of the input; the second, rule is a parameter for the validation. It corresponds to the value 8 in the minlength validation.
Now, to add the validation to our field, we just need to add it in v-validation of the input:

<input type="email" name="email" v-validate:email="{required: true, email: true}"/>

Note: as this validation syntax expect a JSON, I've added a fake rule value to true that will just be dropped during validation.

If you want to force password to follow your rules, you should see how to do it (this is why I didn't list this constraint in our sample).

Now that we have our structural checks, we have to implement one functional check: that both passwords are the same. This check will be a local custom validator inside our Vue component. To add it, you have to add a node validators in component declaration (I also add a data field password that is linked to password input using v-model):

<script>
    new Vue({
        el: "#creationForm",
        data: {
            password: '';
        }
        validators: {
            checkSamePasswords: function(val) {return true;}
        }
    });
</script>

checkSamePasswords is only added to the confirmPassword input because I think the error is linked to the confirmation of the password, even if you change the first one. To check the first input value, I'll take the data attribute created earlier, the method becomes:

checkSamePasswords: function(val) {
    return val == this.vm.password;
}

Inside the function, this refers to the validator and not the Vue component like when you are in function declaration inside methods node. In order to access to data model, we need to use this.vm.

Display errors to the user

Everything we did until now was only to check if data provided by the user are correct, we didn't provide any feedback yet and user is still able to submit the form even with errors! There is no magic that will block the submit process, it's up to us, as developers, to define how validation will appear.

First thing is to block form submission as long as the validation fails. For that we can update the submit input like that:

<input type="submit" value="Create user" v-if="$validator.valid"/>

$validator.valid is a boolean that indicates if the overall validation is a success or not. All validations have to be successful for valid to be true. This is a basic sample and you could have a button disabled instead of not displayed at all.

To have access to each validation, you can use: $validator.*fieldName*.*validation* each of them will be a boolean but, be carefull here true value means that validation failed, to be more precise, having the value to true allows an easier integration of error messages. Let's take email field, we have 3 boolean available:

  • $validator.email.required
  • $validator.email.email
  • $validator.email.checkUserExists

To display an error message for each cases (adapt with your CSS / HTML):


<p v-if="$validator.email.required">Provide an email</p>
<p v-if="$validator.email.email">Please provide a valid email adress</p>
<p v-if="$validator.email.checkUserExists">This email is already in use</p>

For me, it doesn't make sense to display all errors if a mandatory field is not filled so we can adapt the condition like bellow:

<p v-if="$validator.email.required == false && $validator.email.email">Please provide a valid email adress</p>

The error message will only be displayed if the required validation is passed but not the other validation.

There are also some CSS class automatically added to the input but you should manily use these options:

  • valid: when all validations of the field are successful
  • invalid: when at least one validation fails
  • untouched: field has not been focused yet
  • touched: field had the focus and focus moved to another field

Using these combination, you can have some specific CSS rules like (assuming your errors are displayed next to the input with CSS class "error"):

.invalid.untouched ~ .error {
    display: none;
}
to hide errors until the user "touched" the field.

With this sample however, there is one case where the validation fails but no error is displayed. You provides password and confirmPassword with the same value, all validations success for these 2 fields. Then, you update only the first password field. Validation fails because both fields are not equals anymore (and the submit button is not displayed) but the error message is not displayed next to the confirmPassword field. It's because the validation clauses for the field are only recalculate when the field is updated. You could trick the system with event listeners (provided in the plugin even if I think it adds too much complexity) but I consider that as a limit case as I don't think of a user who provide a password twice then only update the first one. If the focus comes back to the second field the error message will be displayed.

Conclusion

First, sorry for this very long post. When I started it I was not thinking having such a long one but I hope I covered most of the basics of this plugin. I find it very useful when you already use VueJS in your application as it provides a pretty straightforward way to dynamically display errors per fields, even with complex validations.
Going further, you can also link Vue-validator with server-side validations in order to check that the email is not already in our user database for instance (but it would be too long here, maybe another post if you want).