How the jQuery validate plugin works internally

August 12, 2012

There are plenty of articles that target how to write custom rules to the jquery.validate plugin but very few targets how this plugin internally works and that’s what we will discuss in this article

this is part of “understanding Asp.net Mvc Unobtrusive Validation” series

  1. How the jQuery validate plugin works internally
  2. Understand the Html generated by the unobtrusive validation in Asp.net MVC
  3. How the unobtrusive jQuery validate plugin works internally in Asp.net MVC

What we will be talking about in this article

  • How to validate a form
  • The validation messages and how they work
  • Add custom validation rules
  • What exactly happens when we call the validate method

How to validate a form ?

There are basically 2 ways to validate your form

1- Use Class names as rules

How it works

We decorate the fields that we want to validate with an html class attribute and that is what will trigger the validation

So if we want a textbox to be required we add to that input element a class value of required

<form action="/" method="post">
  <input id="Name" type="text" name="Name" value="" />
  <input type="submit" value="Submit" />
</form>
$(document).ready(function() {
  $(‘form’).validate();
});

With this method you can define certain classes with multiple rules

Pros & cons of this approach

  • only works with rules that takes no arguments
  • we are using the html class attribute for something not related to its original intent which is a break for separation of concerns principle
  • but still it’s very easy to setup

Using addClassRules method

Using addClassRules function gives us the ability to use compound rules as a single class

$.validator.addClassRules({
  name: {
    required: true,
    minlength: 2,
  },
  zip: {
    required: true,
    digits: true,
    minlength: 5,
    maxlength: 5,
  },
})

This will add 2 new class rules, name and zip so if we have an input element and gave it a class of zip it will be required, the user must only insert digits and the length must be exactly 5 characters

<input class="zip" type="text" name="zipCode" />

Note: to use a custom message for a specific rule in a compound class rules requires a workaround, you have to alias the rules like required to a new rule and in the new rule you define a default message

$.validator.addMethod(
  'newrequired',
  $.validator.methods.required,
  'new name is required'
)

or you can use the title html attribute and it will be the error message for the compound rule

class names validation only works on the validation rules that doesn’t accept any arguments

2- Add rules as JSON object to the validate method

by the name you should have figured out that the validation method takes a json object, we then could specify the fields that we want to validate and the validation rules for it

<form>
  <input id="something" type="text" name="userEmail" />
  <input id="submit" type="submit" value="submit" />
</form>
$(‘form’).validate({
  rules: {
    userEmail: {
      email: true,
      required: true
    }
  }
});

when you pass the rules object to the validate function the key should be the value of the name attribute not the value of the id as you can see in the example the key is userEmail which is the value of the name attribute and the id is something else

Pros & cons of this approach

  • this approach will give us the ability to use more validation rules that require arguments like minlength, remote, equalTo , etc..
  • great and manual control over everything
  • but the user have to make a separate validate function with different options for every form

Adding or removing dynamic rules

Adding rules

To add a rule we should use the rules method on a jquery elements itself after the form is validated and pass the first parameter the string add and the second one an object of rules you want to add for this element (you can also pass a message object for the rules you added)

$('.input').rules('add', {
  required: true,
  messages: {
    required: true,
  },
})

Removing rules

if you want to remove a rule or set of rules you pass the string remove as the first parameter for the rules method then the second will be a string that containing the rules you want to remove separated by a space

$('.input').rules('remove', 'min max')

More manual approach

accessing the validator object after the form is validated and from it access the rules object and then we can extend or modify it

var validator = $('form').data('validator')

validator.settings.rules.objectName = {
  required: true,
}

this approach is very useful if you have an already made rules or messages objects you could extend the rules of the validator with your own

$.extend(validator.settings, { rules: rules, messages: messages })

to understand the validator you can check What exactly happens when we call the validate method section


The validation messages and how they work.

There are 3 ways to provide a validation message

  • pass a messages object to the validate method the messages object consist of key/value pairs the key is the name of the element and the value is an object containing every rule and its message
$('form').validate({
  rules: {
    userEmail: {
      email: true,
      required: true,
    },
  },
  messages: {
    userEmail: {
      email: 'Please enter your email',
      required: '*',
    },
  },
})
  • The value of the title attribute on the element
<input id="Email" title="you have to enter a value" type="text" name="Email" />
  • default message when defining the validation rule and there are built in default messages for the built in rules

These 3 ways override each other based on the priority, passing the messages object is the most important and the default message is the least important


Add custom validation rules.

When we want to add more validation rules than the default ones we use $.validator.addMethod

this method accepts as parameters the following

  • rule name
  • a function that do the validation
  • a default message

the function that do the validation can be in 2 different signatures

 function validationMethod (value, element)
 // OR
 function validationMethod (value, element, params)

lets explain these parameters

  • value: the value of the DOM element that will be validated
  • element: the DOM element itself
  • params : is what you pass as a value to this validation ruleExample what paramswill equal
$('form').validate({
  rules: {
    firstname: {
      compare: {
        type: 'notequal',
        otherprop: 'lastname',
      },
    },
  },
})

in this example the params will equal to

{type:"notequal", otherprop: "lastname"}

Example to add custom rule

$.validator.addMethod(
  'notnumbers',
  function (value, element) {
    return !/[0-9]*/.test(value)
  },
  'Please don’t insert numbers.'
)

What exactly happens when we call the validate method.

When you call validate on a form mainly couple of things happens behind the scene

  • Create a validator object with all the rules and options and attach it to the form.

  • The validate method attaches the validator using $.data , you can get it by selecting the form and calling the jquery $.data function and passing it validator. The validator object is all the metadata for the validation giving us the ability to access the validate options at anytime in the page cycle

  • using this object you can change at runtime the options that you passed to the validate method like adding or removing rules, change what happens when the field is valid or invalid or even provide an ignore selector

//getting the validator
var validator = $('.selector').data('validator')
  • Note: when you call validate on a form that was already validated it will just return the validator object using also $.data and all the options passed to validate method will be omitted
var validator = $('.selector').validate(/* rules will be omitted */)
  • subscribe events to the form itself

  • What will happens when you click submit and there are invalid elements is you will trigger the validation of the fields, if one of them is not valid then the validate plugin will listen to it more closely to check if it is valid or not The events that are subscribed to the form are click, focusin, focusout, keyup, submit

    you can disable these events by passing them as keys to the validate method and false as their value

$('.selector').validate({
  onfocusout: false,
  onkeyup: false,
  onclick: false,
  onsubmit: false,
})

See also:


Nadeem Khedr

Written by Nadeem Khedr citizen of the world, you can find me on Twitter & Github