December 2nd, 2010

JavaScript Form Validation

GValidator is a simple, user-friendly and open-source client-side form validation library

— Matt Fellows —

JavaScript Form Validation

Want to validate user input for an (X)HTML form without embedding a single line of JavaScript, without having to worry about violating semantics, and all the while providing a reactive, user friendly experience?

Introducing GValidator – a powerful, extensible yet easy to implement JavaScript library that provides constant feedback during form completion. To use the library all you need to do is include it.

Example form with validation icons


Table of Contents

  1. Project goals
  2. Download
  3. Examples
  4. XHTML API
  5. Options
  6. Design
  7. JS API
  8. Extending with Plugins
  9. I8N
  10. Extending with OOP
  11. Browser support

The Aim

The aim of GValidator is to provide the following:

  • A user-friendly experience for our visitors
  • Semantically clean code
  • Standards compliant code
  • Cross browser compatibility
  • Reusable JavaScript code
  • Code flexibility and extensibility

The Code

GValidator now has a Google Code project. To get the latest version, post bugs, comment on or just look about visit: http://code.google.com/p/gvalidator

  • Download the GValidator library, along with examples and CSS

Actually, for basic forms no extra coding is needed other than to include the JavaScript file and to add appropriate class names to your form fields. Here is an example form:


<form action="/action/" method="post" class="gform" ><br />  <input type="text" name="firstname" class="firstname required" />    <br />  <input type="text" name="lastname" class="lastname required" id="lastname"/><br />  <input type="text" name="subject" class="text required" id="subject" /><br />  <input type="text" name="captcha" class="captcha required" id="captcha" /><br />  <input type="text" name="phone" class="phone required" id="phone"/><br />  <input id="submit" type="submit"/><br /></form> 

There are a few things to notice here;

  • The form is given a class attribute of “gform”. This is what activates the automatic form validator
  • The fields for validation are given various class names depending on how we wish to validate them. i.e. class=”name”, class=”phone”, class=”text” etc.
  • To make a field required, simply add the class ‘required’. You can still use the library on non-required fields, as it will cleanse them and validate if not correctly completed.
  • There is no embedded JavaScript functions or invalid semantic markup here. Just clean, straightforward XHTML

The Example

There are 4 examples, ranging from simple to advanced implementation:

  • See the basic example of GValidator – no javascript coding required
  • Plugin – extends GValidator with a validation function type for an IP 4 address
  • Internationalization – translates GValidator into German using a translation file so that your forms will have internationalized client side validation.
  • Customization – tailors the default behaviour of GValidator on a global and a per-form basis, using only basic javascript

All of the examples are available for download on the Google code GValidator site.

Field Types (default XHTML API)

The following are the field types and corresponding class names that are included in the default implementation. They should cover most cases. If you require more than this or customisation, then you can extend the functionality as discussed below.

Form element Description Class name
text Generic text input. Allows any characters except the following – ().;<> and is not mandatory text
text Name field name
text Phone number field. Allows between 8 – 12 digits only. phone
text Email field email
text Captcha field captcha
text Re-Captcha field recaptcha
select Generic combo box. Requires the user to select an option with a non-empty value select
radio group Generic radio group. Requires that the user selects at least one of the options radio
check box Generic checkbox group. Requires that the user selects at least one of the options checkbox
password Password field. Requires a password of at least 8 characters, and containing one or more of a digit, lowercase and uppercase characters. password
password Password confirmation field. Verifies that the confirmed password is the same as ‘password’. confirmpassword

GValidator Options

GValidator has the following options, passed in to a variable with name ONEGEEK.forms.GValidator.options.
This variable is a literal object, containing key/value pairs.

Parameter Accepted Values Description
reqShow [Boolean] Automatically add the required char to labels? (Defaults to true)
reqChar [String] Character used to indicate a required field (Defaults to ‘*’)
reqPlacement [‘after’, ‘before’] Position of required character. Can be ‘before’ or ‘after’ (Defaults to ‘after’)
autoFocus [true,false] Automatically focus the first form element on page load (Defaults to true)
supressAlert [Boolean] Suppresses the javascript alert on an invalid form submission.
highlightFields [Boolean, String] If not false, Will apply a class name of ‘highlight’ or the value of String to any invalid field on form submission attempt.
Element level messaging display options
eMsgFormat [‘open’,’compact’] How to display messages next to the field.
‘open’ refers to always showing the message (Default)
‘compact’ only shows if the user performs an event on the field’s icon.
eMsgEventOn [String (DOM Event)] Only used if eMsgFormat’compact’. Event used to trigger message display toggle (Defaults to ‘click’)
eMsgEventOff [null, ‘click’, ‘mouseout’ …] Only used if eMsgFormat’compact’. Event used to trigger message hide toggle. (Defaults to ‘click’)
Cannot be the same as ‘eMsgEventOff’ (they would cancel each other out)
Form level messaging display options
fMsgFormat [null, String, Function] How to display errors at the form level.
null displays an alert to the user indicating there are errors to be corrected. See fMsg to override default message. (Default)
String Pass in an id reference to a container div to place the errors in as a <ul”gvErrorsList”>
Function To do something custom on form submission error, pass in a function that accepts 1 parameter containing all of the error fields (ONEGEEK.forms.AbstractFormField[])
fMsg [String] A string alert to display on error. (Defaults to “Please correct the highlighted errors!”)
Image parameters for ‘compact’ messages
icons: { [Object]
ok [String] Path to the ONEGEEK.forms.FIELD_STATUS_OK state icon
info [String] Path to the ONEGEEK.forms.FIELD_STATUS_INFO state icon
error [String] Path to the ONEGEEK.forms.FIELD_STATUS_ERROR state icon
}

GValidator Library Design

The library was designed with simplicity and extensibility in mind. The basic idea was to create an abstract class hierarchy that could be quickly and easily extended to change the validation function for a new field type. This hierarchy exists in three tiers allowing for the following object types:

  • One third (top) level AbstractFormField class, which provides the skeleton that all AbstractFormField subclasses inherit from
  • A finite number of second level AbstractFormElements which provide the basic implementations for the different form elements (i.e. <input>, <select> etc.)
  • An infinite number of first level ConcreteFormElement objects which provide the concrete validation implementations (i.e. validate a phone number field)

By implementing the library in this way, we allow for simple extensibility by implementing subclasses at the lowest level.

JavaScript API

Read the JavaScript API or download it from Google Code.

Class Hierarchy

Basic Form Field Class Hierarchy

Extending GValidator

Creating new validation types for GValidator is easy, they are added in the form of plug-ins. All you need to do is add object keys to the ONEGEEK.forms.GValidator.plugins object with the class name of the validator you wish to add.

Customisation example

Let’s say we’d like to create a new validator for an IP 4 Address type on a text field, using the class name ‘ip4address’.

The validation function must:

  • Validate the input of an IP 4 Address type i.e. 127.0.0.1
  • Remove non-allowed characters from the field before validation
  • Have custom messages for each state of the field
  • Additionally, the validator must highlight the field on error and clear the highlight on success

Step 1: Create the plugins object and add your new type and extend a type

Place the following object in an external JavaScript file after gvalidator.js has been added to the page.

The new type will use the className ‘ip4address’ to activate the validator on the field.

ONEGEEK.forms.GValidator.plugins = {
ip4address: {
_extends:     'AbstractTextField',
...
};

Note that the _extends key is set to ‘AbstractTextField’ because we are validating a Text field. Other options are ‘ComboBox’, ‘RadioButton’ or ‘Checkbox’ at the second level (see above). Of course, you can extend existing elements such as ‘NameField’ if you wish.

Step 2: Override existing instance variables

Here we override the AbstractFormField messages and AbstractTextField regex and cleanRegex variables. These last variables are used to validate the data and clean out invalid characters respectively (Note: regex has been shortened for display).

ONEGEEK.forms.GValidator.plugins = {
ip4address: {
...
regex:        /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2
cleanRegex:   /[^0-9\.]/g,
contextMsg: 'Please enter a valid IP 4 Address i.e. 127.0.0.1',
errorMsg: 'Please enter a valid IP 4 Address i.e. 127.0.0.1',
successMsg: 'Thanks',
...
}
};

Step 3: OPTIONAL Override validation and other functions

If you are content to keep the validation behaviour consistent with other text fields, then you can stop here – how easy was that?

If, however, you want to do some custom validation behaviour then we need to override the existing validate() function:

	ONEGEEK.forms.GValidator.plugins = {
ip4address: {
...
validate: function() {
if(!this._validate()) {
this.highlight();
} else {
this.unHighlight();
}
},
highlight: function() {
this.field.style.background = 'rgb(200,0,0)';
},
unHighlight: function() {
this.field.style.background = 'rgb(255,255,255)';
}
}
};

Note that the validate function makes a call to _validate(). This is actually the parent (previously overridden) validate function. In fact, any attribute or function that you override will be preserved with a ‘_’ prefix so that you can make reference to it if needed. This means, we can call the existing validation function that we like, and enhance it by highlighting the field. Also note that you can attach any function/attribute that you desire and they will be attached to the this of the new object type, effectively extending the class. Be careful not to clash with existing variables/functions unless you intend to (Check out the API or download it from Google Code if unsure)

Full customisation code

Here is the entire code listing for the customisation (regex has been shortened for display):

	ONEGEEK.forms.GValidator.plugins = {
ip4address: {
_extends:     'AbstractTextField',
regex:        /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2
cleanRegex:   /[^0-9\.]/g,
contextMsg: 'Please enter a valid IP 4 Address i.e. 127.0.0.1',
errorMsg: 'Please enter a valid IP 4 Address i.e. 127.0.0.1',
successMsg: 'Thanks',
validate: function() {
if(!this._validate()) {
this.highlight();
} else {
this.unHighlight();
}
},
highlight: function() {
this.field.style.background = 'rgb(200,0,0)';
},
unHighlight: function() {
this.field.style.background = 'rgb(255,255,255)';
}
}
};

Internationalisation

Internationalising client-side validation in GValidator is easy. It should work with any almost any language.

Note: GValidator does not change the labels on the form or any other content on the page other than content related to the validation of the form. It assumes that the page itself has already been translated and requires form validation specific to that language.

To specify a language translation for a form, simply do the following:

  1. Apply the W3C attribute ‘lang’ to the <form> with the value of the language to translate into i.e. lang=”DE” (see a list of valid values)
  2. Create a variable with the format ONEGEEK.forms.GValidator.translation.<LANG> i.e. ONEGEEK.forms.GValidator.translation.DE (Note that uppercase is important)
  3. In that Object, override messages/parameters for existing validator types using the className of the field you wish to override i.e. ‘username’
  4. To set defaults across ALL validator types, use the special top-level key ‘defaults’. These will only be used in the case that a translation is not available for a given class

I8N example

Create a form specifying the lang attribute:

<form lang="DE" ...>

Create an JS file containing a variable like the following:

ONEGEEK.forms.GValidator.translation.DE = {
defaults: {
successMsg: 'Danke',
contextMsg: 'Bitte füllen Sie',
errorMsg: 'Kaputt! Es wurde ein Fehler beim Überprüfen diesem Bereich',
emptyMessage: 'Pflichtfeld, füllen Sie bitte.',
},
firstname: {
contextMsg: 'Wir möchten Sie von Ihrem Namen zu nennen'
},
...
};

To set the form level error alert messag, override the ‘fMsg’ property in the options config (see Customisation abve) like the following:

ONEGEEK.forms.GValidator.options = {
fMsg: "Bitte korrigieren Sie die markierten Fehler!"
};

Extending GValidator (Advanced)

If you prefer to code in a more OOP (and I use that term very loosely) type approach, with the added benefit of code completion in some editors, this might be for you.

To create your own validation types, you need to do the following things:

  1. Create a class at the first level, overriding the AbstractFormElement of your choice. i.e. To create a UsernameFormField class you would subclass the AbstractTextField class
  2. Override any instance variables of ONEGEEK.forms.AbstractFormField if necessary (Read the JavaScript API or download it from Google Code)
  3. Override the validation function (and any other functions necessary) to do the custom form field validation
  4. Register the new class with FormFieldFactory

We will run through these steps in the following example.

Customisation example

Lets say we would like to create a new field type username for validating usernames. The requirements are as follows:

  • It must be between 8-10 alpha-numeric characters
  • It must not already exist in the database
  • It is a required field

Step 1: Subclass AbstractFormElement

Create a new class ONEGEEK.forms.GenericTextField and subclass ONEGEEK.forms.AbstractTextField.

	ONEGEEK.forms.UsernameTextField = function(field) {
this.field = field;
...
}
ONEGEEK.forms.UsernameTextField.prototype = new ONEGEEK.forms.AbstractTextField();

Step 2: Override existing instance variables

In this case, we need to make the field required and we want to validate the field using a regular expression. We can override the instance variables in ONEGEEK.forms.AbstractTextField to achieve this. Override the following instance variables like so:

this.field = field; // This MUST alwys be here
this.regex = /^([a-zA-Z0-9-\'\s]{8,10})$/g
this.cleanRegex = /[^0-9a-zA-Z-\'\s]/g
this.errorMsg   = 'Your username must be between 8 and 10 characters';
this.contextMsg = 'You will use this to login. It must be between 8 and 10 characters';

Step 3: Override the validation function

The validation function is where most of the action happens. This function is responsible for checking whether the data has been modified and is valid, and setting the appropriate state of the field (INFO, OK, ERROR). This is where your custom AJAX code would go.

Assuming that an AJAX function called checkUsername(name, field) exists, which takes a username and a ConcreteFormElement object, this is how you would implement the validation function:

this.validate = function() {
this.clean();
this.pattern = new RegExp(this.regex);
var validated = this.pattern.test(this.field.value);</p>
if (validated) {
// Regex validated, now use AJAX to check if username exists
// On successfull AJAX validation set state to OK
// On failure of AJAX validation set state to ERROR
checkUsername(this.field.value, formField);
} else {
if (this.modified == false) {
this.setState(ONEGEEK.forms.FIELD_STATUS_INFO);
} else {
this.setState(ONEGEEK.forms.FIELD_STATUS_ERROR);
}
}
return true;
}

Step 4: Register the class with FormFieldFactory

Your custom validation function wil never be used unless you register with FormFieldFactory and tell it which classes you want it to automatically handle. Let’s say that you want to use the class “username” with this function as in the example form element below:

<input type="text" name="username" class="username"/>

To get your new function to handle this, you simply do the following:

formFieldFactory.registerFormField('username', 'UsernameTextField');

Now when you load the page your new function will handle the validation!

Full customisation code

Here is the entire code listing for the customisation:

ONEGEEK.forms.UsernameTextField = function(field) {
this.field = field;
this.regex = /^([a-zA-Z0-9-\'\s]{8,10})$/g
this.cleanRegex = /[^0-9a-zA-Z-\'\s]/g
this.errorMsg = 'Your username must be between 8 and 10 characters';
this.contextMsg = 'You will use this to login. It must be between 8 and 10 characters';</p>
this.validate = function() {
this.clean();
this.pattern = new RegExp(this.regex);
var validated = this.pattern.test(this.field.value);

if (validated) {
// Regex validated, but use AJAX to check if username exists
// On successfull AJAX validation set state to OK
// On failure of AJAX validation set state to ERROR
checkUsername(this.field.value, this);
} else {
if (this.modified == false) {
this.setState(ONEGEEK.forms.FIELD_STATUS_INFO);
} else {
this.setState(ONEGEEK.forms.FIELD_STATUS_ERROR);
}
}
return true;
}
}

// Subclass Abstract FormField class
ONEGEEK.forms.UsernameTextField.prototype = new ONEGEEK.forms.AbstractTextField();

// Register the field types with FormFieldFactory
formFieldFactory.registerFormField('username', 'UsernameTextField');

GValidator Browser Support

The library has been tested successfully on the following browsers on Windows:

  • Internet Explorer 6.0
  • Internet Explorer 7.0
  • Internet Explorer 8.0
  • Mozilla Firefox 1.0.6
  • Mozilla Firefox 2.0.0.7
  • Mozilla Firefox 3.0
  • Mozilla Firefox 3.5
  • Safari 3 Beta
  • Opera 9.25
  • Netscape Navigator 8.0
  • Netscape Navigator 9.0.0.1
  • Google Chrome

and the following browsers on Linux:

  • Mozilla Firefox 2+
  • Opera 9.62
  • Epiphany 2.26