Aiming for elegance, one thought at a time

Javascript Form Validation

Posted: May 23rd, 2010 | Author: | Filed under: IT | No Comments »

This is an incredibly common problem, and there’s really no reason to reinvent the wheel. That said, yesterday I thought of (what I think is) a rather neat way of solving the problem. So I’ve deliberately not looked in-depth at how others have solved this particular problem, and instead made a quick sketch of my solution. When I do look, I think I’ll be looking at the jQuery Validation Plugin.

In short, this model is inspired by jQuery’s ability to chain queries together, to give succinct, powerful syntax. There are two essential things that I want to be able to do:

  1. Check if a condition is present
  2. Assert that something should be so

My aim is to be able to do this with code that looks like this:

vl.ifEqual("detailrequired","Full")
  .assertNotEmpty("If full details are required,"
                  + "contributions must be entered",
                  "contributions");

But let’s start at the beginning. Form validation: there are many levels. Let me enumerate some:

  1. Required fields
  2. Fields having the correct format
  3. Inter-field validation (eg a start date falling before an end date)

In this sketch, I’m particularly thinking of the third level of form validation. In the example of a start and end date, all I want to do is check that the start date falls before the end date, and it it does, throw an error. I can do that with this code (error handling removed for brevity):

var startdate = Date.parse(document.getElementById("startdate").value);
var enddate = Date.parse(document.getElementById("enddate").value);
if (startdate > enddate) {
    alert("Start date must fall before the end date");
}

Simple enough, but rather wordy – particularly when you get in to handling errors and unexpected input. A more complex example might be to check the value of one field, and depending on its value, apply a particular rule. For example, if a field detailsrequired equals full, then a number of other fields are required. This could be achieved with this Javascript:

if (document.getElementById("detailsrequired").value=="Full") {
    if (document.getElementById("contribututions").value=="") {
        alert("If full details are required, "
               + "contributions must be entered");
    }
}

These individual samples aren’t very complex, but once you add code to handle exceptions, then they blow out a little bit. It’s also quite verbose. To achieve the syntax outlined above, where I can chain the checks and assertions together, I need to create an object that returns a reference to itself when you call any of its methods – the same way as jQuery works.

In the following code excerpt, I create two functions, and then bind them to a function object, ValidationLibrary. First a word on the function object: it has a single property, ‘check’, that is set by its single parameter. This parameter is used by the function assertEmpty. If this.check is true, then it will apply the assertion. If not, it doesn’t do anything.

The ifEqual function takes two parameters and compares them. If they are equal, it returns the parent object unaltered. On the other hand, if it they are unequal, it returns a new ValidationLibrary with check set to false – thus disabling any subsequent assertions.

function ifEqual(a, b) {
    if (a!=b) {
        return new ValidationLibrary(false);
    }
    return this;
}

function assertNotEmpty(msg, a) {
    if (this.check) {
        if (a=="") {
            this.error(msg);
        }
    }
    return this;
}

function ValidationLibrary(check) {
     this.check = check;
     this.assertNotEmpty = assertNotEmpty;
     this.ifEqual = ifEqual;
} 

With this framework, the example above becomes:

var vl = new ValidationLibrary(true);
vl.ifEqual(f("detailsrequired"),"Full")
  .assertNotEmpty("If full details only are required, "
                    + " contribution must be provided",
                  f("contribution"));

Note: I’ve created a function f(id) that returns the value of a form field, given a particular ID. If the form field contains a date, a Date object will be returned. If the form field contains a number, a Number object will be returned. Otherwise, a string will be returned.

With this framework, there’s a lot less boilerplate in order to get the same effect, and behind the scenes there is (or is in theory) a lot more error checking.

As above, this is only a rough sketch to capture the idea. I’m still to go and look at how other people have solved this same problem. And to be usable, a lot more would need to be done on this framework: the way assertions are reported in particular would need a lot of work, and even a cursory glance shows the the jQuery Validation plugin does a much better job of simple validations like making a field mandatory.

That said, the main idea I wanted to jot down was a way of handling more complex validations in an elegant way: I’m curious to see what other options are already in use.

In the meantime, please feel free to check out the rough demo and peruse the full javascript files, ValidateLibrary.js and FormValidations.js.

Tags: , , , , , ,