Custom Validators with Validatious

published Aug 10, 2010

When I talked about Validatious previously, I had written almost no Javascript and had no need for any validations besides making sure that fields were required and of a certain minimum length.

On another project, I needed to validate some North American phone numbers and Canadian postal codes. It turned out to be really simple to add custom validations. Here’s how it’s done.

First, here’s a form:

<form id="test_form" class="validate">
  <div class="formset">
  <label for="address">Address</label><br />
  <input type="text" id="address" name="address" class="required" />
  </div>
  <div class="formset">
    <label for="postal_code">Postal Code</label><br />
    <input type="text" id="postal_code" name="postal_code" class="required cndpostalcode" />
  </div>
  <div class="formset">
    <label for="phone_number">Phone Number</label><br />
    <input type="text" id="phone_number" name="phone_number" class="required phone" />
  </div>
</form>

Note that I’ve added a class of cdnpostalcode to the postal code input and a class of phone to the phone number input. You still need the required class to turn on the validation.

This won’t do anything other than require that the inputs be filled out yet, as we haven’t added our custom validators in. To register a validator, you do something like this:

v2.Validator.reg('validatorClassName', function(field, value, params) { 
   return true /* some call back that returns true or false */ 
})

Most of the time, the callback is a regular expression. Let’s tackle the Canadian Postal Code one first, as they’re a bit simpler.

A Canadian Postal Code looks like A1A 1A1 or S7J 3A2 or H0H 0H0 ( bet you didn’t know that Santa lived in Canada! ). It’s letter-number-letter space number-letter-number. The space is optional, too. So, a regular expression to match a Canadian Postal Code might look like this:

/^\w\d\w\s*\d\w\s$/

We’ll register the class cdnpostalcode to trigger this validation like this:

v2.Validator.reg('cdnpostalcode', function(field, value, params) {
  return /^\w\d\w\s*\d\w\d$/.test(value)
})

The phone number validator is exactly the same, except the regular expression is a bit more hairy. This regex is from regexlib.com (I added in the part that accepts an extension).

v2.Validator.reg('phone', function(field, value, params) {
  return /^([0-9]( |-)?)?(\(?[0-9]{3}\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})[ x0-9]*$/.test(value)
})

If we add those two chunks of Javascript to the HTML that calls our form, then they will validate the postal code and phone number correctly. The only problem is that the validation error message will be something like “Postal Code does not pass cdnpostalcode validator”. Not very pretty. There are a few more options to Validator.reg that will allow us to fix that.

The signature for Validator.reg looks like this (it’s in src/core/validator.js):

reg: function(name, fn, params, message, aliases, acceptEmpty) {
}

So far, we’ve only used the first two parameters (name and fn). The params argument would allow us to specify the parameters used in the validator. We don’t need that, so we’ll pass in null. Then, we can set the default message. Like this:

var postal_code_message = "You must provide a valid Canadian Postal Code"
v2.Validator.reg('cdnpostalcode', function(field, value, params) {
  return /^\w\d\w\s*\d\w\d$/.test(value)
}, null, postal_code_message)

similarly for the phone validator:

var phone_message = "You must provide a valid phone number"
v2.Validator.reg('phone', function(field, value, params) {
  return /^([0-9]( |-)?)?(\(?[0-9]{3}\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})[ x0-9]*$/.test(value)
}, null, phone_message)

Here’s what the full HTML looks like. You can see this form in action here. If you’re intrigued, make sure to go check out Validatious.

<html>
  <head>
    <title>Demo: Custom Validations with Validatious</title>
    <style type="text/css">
      ul.messages {
        list-style-type: none;
        padding: 0;
        margin: 15px 0 0 0;
      }

      .error ul.messages li {
        color: red;
        padding: 0;
        margin: 0;
      }
    </style>

  </head>
  <body>
    <h1>Demo: Custom Validations with Validatious</h1>
    <form id="test_form" class="validate">
      <div class="formset">
      <label for="address">Address</label><br />
      <input type="text" id="address" name="address" class="required" />
      </div>
      <div class="formset">
        <label for="postal_code">Postal Code</label><br />
        <input type="text" id="postal_code" name="postal_code" class="required cdnpostalcode" />
      </div>
      <div class="formset">
        <label for="phone_number">Phone Number</label><br />
        <input type="text" id="phone_number" name="phone_number" class="required phone" />
      </div>
    </form>
    <a href="/2010/08/custom-validators-with-validatious.html">Back to the blog post</a>

    <script src="/demos/javascripts/validatious.min.js" type="text/javascript"></script>
    <script type="text/javascript">
      v2.Field.prototype.instant = true; // make the validations happen instantly

      var postal_code_message = "You must provide a valid Canadian Postal Code"
      v2.Validator.reg('cdnpostalcode', function(field, value, params) {
        return /^\w\d\w\s*\d\w\d$/.test(value)
      }, null, postal_code_message)

      var phone_message = "You must provide a valid phone number"
      v2.Validator.reg('phone', function(field, value, params) {
        return /^([0-9]( |-)?)?(\(?[0-9]{3}\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})[ x0-9]*$/.test(value)
      }, null, phone_message)
    </script>

  </body>
</html>
blog comments powered by Disqus