A Javascript framework for client side web application data validation

by Faustino Dina Rivas

Published: May 8, 2002
Last Updated: May 8, 2002

Copyright

This article is Copyright 2002 by the author.
Any form of copying of the materials presented here, for any reason other than for an individual user's personal reference without the permission of the author is prohibited. Further distribution of the material is strictly forbidden.

Abstracts

The purpose of this paper is to describe a framework for declarative validation of input fields on web forms on the client side of a web application by using DHTML facilities. A javascript class implementing the framework is presented, and sample data validation functions to be used within the framework are explained.

Keywords

client side validation, javascript, dhtml

Introduction

Client side validation of web form can be a repetitive, tedious and error prone process. This paper will propose a simple framework to consolidate input field validation functions into an easy to reuse and extend set of validators.

The client-side data validation problem

...

Our approach

Our approach will be to make the input field validation as declarative as possible, by including custom properties into the standard input field that describe the validation that should be executed over the field, and the error messages that should appear. Then before submitting the form, javascript function will browse all the input fields of the form and check its values against the defined validation routines. The programmer can freely define validation routines so it is easy to add support to any custom data type. You can use simple validation routines for autocontent validation, but you are not limited to that. The possibility to define custom validation routines gives you full flexibility in handling complex validations, such as cross-validation between interdependent elements in the form.

Custom properties

Our framework uses the following custom attributes:

dvalidate_type specifies the data type of the input date. This data type is the key to access the validation function.
dvalidate_required (true or false) specifies if the value is required
dvalidate_msgrequired error message to display if the attribute dvalidate_required was set to “true” and value was not supplied.
dvalidate_msginvalidtype error message to display if the registered validation function registered with the key dvalidate_type, fails the validation.

So the validation declaration for an input text can look like this:

<input type="text" name="PostalCode" size="13" dvalidate_type="pc" dvalidate_required="true" dvalidate_msqrequired="The Postal Code should be specified." dvalidate_msginvalidtype="The supplied Postal Code is not valid.">

All you should do is to supply a validation to handle input from this form field and register it within the framework with the key “pc”.

Validation function

The "prototype" for the validation function for our framework looks like this:

function validator(value, node) 

It accepts two parameters: value is the value the user input into the form field; node is the node corresponding to the input field as parsed by the DHTML engine. Passing the node parameter gives the opportunity to access additional custom parameters. It can be use for further extending 
The validating function should return null if the validation fails, or the validated value. As you can guess, the framework raises the defined error message in case of receiving a null from the validator function. But also the framework overwrites the actual value of the input field with the one returned by the validator, so you have chances for making such things like trimming strings, or normalizing dates, times, etc, before sending the data to the server. 

Note there is no need to supply a validating function for checking 

Validating function examples

A simple example of a function expecting integer input can be:

function Validator_int(value, node)
{
  return (String(parseInt(value, 10)) == value) ? value : null;
}

Supposing you have defined a trim function for the string object, we can format the validated data by

function Validator_string(value, node)
{
  return value.toUpperCase().trim();
}


The usage of the node parameter can be illustrated with the following example. Here we will validate an integer to be in a specified range. The range limits can be declared by using two additional custom attributes within the input tag. Let modify the postal code input tag to include range validation attributes:

<input type="text" name="PostalCode" size="13" 
	dvalidate_type="pc" 
	dvalidate_required="true" 
	dvalidate_msqrequired="The Postal Code should be specified." 
	dvalidate_msginvalidtype="The supplied Postal Code is not valid." 
	dvalidate_number_min="10000" 
	dvalidate_number_max="99999">

Then we can define a validating function that uses these extra attributes:

function Validator_intRange(value, node)
{
  // check first if the value is a valid integer
  value = Validator_int(value, node);
  if (value == null)
    return null;

  // then validate against the declared min bound...
  var attrMinValue = node.getAttribute("dvalidate_number_min");
  if (attrMinValue != null && Number(value) < Number(attrMinValue))
    return null;

  //...and max bound
  var attrMaxValue = node.getAttribute("dvalidate_number_max");
  if (attrMaxValue != null && Number(value) > Number(attrMaxValue))
    return null;

  //if anything went well, return the value to signal success
  return value;
}

Initializing the framework

The framework is packaged in a separate file for including, so befor using it you should command the javascript engine to include it by 

<script language="javascript" src="/scripts/Validation.js"></script>

Then you should create an instance of the Validation "class". This is the class that encapsulates the framework. Validation instance can be created as a global object, outsude all functions in the page to be validated.

var validation = new Validation();

Down we will describe the interns of the Validation class, but actually the only yo need to know to put it to work is the way to register our callback validation functions.

Registering the validation function

Each used validation function should be registered within the framework. This is made by invoking the add method of the Validation class. In a full-featured object-oriented language it would be one of our two public methods. It needs two parameters: the data type key, and the handling function associated to this data type:

validation.add(type_key, associated_validation_function);

· type_key is the same key that we used in the declaration of the input field in the form under the property dvalidate_type.
· associated_validation_function is the name of the function you defined to handle the validation for this data type. In javascript syntax it is the name of a function defined according to the guidelines described in Validation function (see above).

For example we will register the type "pc" of our above example, to be validated using the Validator_intRange function also already explained before
validation.add("pc", Validator_intRange);

You should register a validation function for each data type declared in the custom property dvalidate_type of your form. 
That is all the configuration needed. The only you need now is know how to fire the validation framework to work.

Invoking the validation

To fire the validation process you should invoke the validate method of our Validation class.

validation.validate(theForm);

validate() method returns true if evrething goes well, or false if at least one of the validation function signals error.
Typically you will launch your validation task at the moment the user clicks the submit button. Then you can do something like that

<form onsubmit="return(validation.validate(this))" >

Full simple example

<html>
<head>
  <title>Validation Framework Example</title>

  <!-- Include framework class -->
  <script language="javascript" src="Validation.js"></script>

  <!-- In this block we will define the validation functions: Typically you will define these functions on a separate file
          and include it here, but we will define them here to simplify understanding -->
  <script language="javascript">

    function Validator_int(value, node)
    {
      return (String(parseInt(value, 10)) == value) ? value : null;
    }

    function Validator_stringToUpper(value, node)
    {
      return value.toUpperCase();
    }

    function Validator_intRange(value, node)
    {
      // check first if the value is a valid integer
      value = Validator_int(value, node);
      if (value == null)
        return null;

      // then validate against the declared min bound...
      var attrMinValue = node.getAttribute("dvalidate_number_min");
      if (attrMinValue != null && Number(value) < Number(attrMinValue))
        return null;

      //...and max bound
      var attrMaxValue = node.getAttribute("dvalidate_number_max");
        if (attrMaxValue != null && Number(value) > Number(attrMaxValue))
          return null;

      //if everything went well, return the value to signal success
      return value;
    }

    <!-- Initialize the framework -->

    var validation = new Validation();
    validation.add("int", Validator_int);
    validation.add("stringUppercase", Validator_stringToUpper);
    validation.add("intRng", Validator_intRange);

  </script>
</head>

<body>

  <form onsubmit="return(validation.validate(this))">
    <table>
      <tr>
        <td>Name (upper case, required): </td>
        <td><input type="text" name="Name" size="13" dvalidate_type="stringUppercase" dvalidate_required="true" dvalidate_msqrequired="You should specify your name." dvalidate_msginvalidtype="(every string is valid)"></td>
      </tr>
      <tr>
        <td>Age (integer value, optional): </td>
        <td><input type="text" name="Age" size="13" dvalidate_type="int" dvalidate_required="false" dvalidate_msqrequired="(not required)" dvalidate_msginvalidtype="This value should be an integer."></td>
      </tr>
      <tr>
        <td>Postal Code (integer, required, in the range 10000 - 99999): </td>
        <td><input type="text" name="Age" size="13" dvalidate_type="int" dvalidate_required="true" dvalidate_msqrequired="You should specify your Postal Code." dvalidate_msginvalidtype="The Postal Code should be a number betwen 10000 and 99999."></td>
      </tr>
      <tr>
        <td colspan="2"><input type="submit" name="Submit"></td>
      </tr>
  </form>

</body>
</html>

The framework class explained

The Validation class encapsulates all the framework. It is implemented in the Object-Oriented feel that gives Javascript. Note we use the following notational convention:

The function Validation() is our Javascript constructor. Apart of redefining the global functions as member of the object, we also define a collection to hold the mapping between data type keys and the corresponding handling function. 

this.aValidationMap = new Array();

This map is implemented by using the Array objects working like a Perl associative array or a Java Map class.

The function Validation_add allows us to register the mapping data type key -> validation function. It just stores tthe function object under the specified key 

function Validation_add(aKey, aHandlingFunction)
{
  this.aValidationMap[aKey] = aHandlingFunction;
}

Functions Validation_nodeGetValue and Validation_nodeSetValue are just helper function to get and set the value associated to an input field. Normally for the standard input type="text" we obtain the value we want to check from the property value. But for the input type="checkbox", normally we would like to get the state checked/unchecked for the node. I did not needed this feature, so I did not develeoped further the switch(aNode.tagName), but any way the layout is here for future extension. So for this implementation simply think Validation_nodeGetValue is an alias for aNode.value; and Validation_nodeSetValue, for aNode.value = aNewValue

The Validation_trim() function, is just an implementation of the very useful Java function String.trim(). Why not is it implemented in Javascript yet?

Then the Validation_validate(aForm) function does all the job. It takes a form object as parameter and iterates all the form elements looking for our custom attributes. 

When it find dvalidate_required == true, it checks if the trimmed value of the input element is a empty string. If so, it displays the message we defined in dvalidate_msqrequired attribute and returns false to signal the validation failure.

When it finds a dvalidate_type attribute, it calls the defined validating function, from the validation map. According to the return obtained from the callback function, it displays the failure message corresponding to dvalidate_msginvalidtype and returns null, or overwrites the validated value with the value returned from the validation function. This trick gives us flexibility to do some preformatting on the validated value. 

That is all. If all the form elements pass the validation check, then the Validation_validate function returns true, and the data can be safely send to the server.

Compatibility

This frameworks was developed and tested with Internet Explorer 5.0 but it should work also in Internet Explorer 4. It is based in DHTML standard features but also uses some proprietary methods that can be easily substituted by DHTML standard. Netscape browsers only started to support standard DHTM  since version 6. It should be not difficult to adapt this framework for cross-browser (Netscape 6 - Internet Explorer 4) compatibility.

A Navigator 4 compatible version of this framework is also available and will be explained in a next article.

Source Code

The sample source code for this article is available in two files:

1