Sunday, 17 August 2008
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.
The aim of GValidator is to provide the following:
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
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" >
<input type="text" name="firstname" class="firstname" maxlength="30"/>
<input type="text" name="lastname" class="lastname" id="lastname" maxlength="30"/>
<input type="text" name="subject" class="text" id="subject" maxlength="30"/>
<input type="text" name="captcha" class="captcha" id="captcha" maxlength="30"/>
<input type="text" name="phone" class="phone" id="phone" maxlength="12"/>
<input id="submit" type="submit"/>
</form>
There are a few things to notice here;
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 | Generic required text input. Allows any characters except the following - ().;<> and must be completed | genericrequiredtext |
| 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 text field. Displays a context and error message related to the RE-CAPTCHA system | recaptcha |
| textarea | Generic textarea input. Allows any characters except the following - ().;<>. Not require | text |
| 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 |
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:

To create your own basic validation functions, you need to do the following things:
Lets say we would like to create a new field type username for validating usernames. The requirements are as follows:
Create a new class ONEGEEK.forms.GenericTextField and subclass AbstractTextField.
ONEGEEK.forms.UsernameTextField = function(field) {}
ONEGEEK.forms.UsernameTextField.prototype = new ONEGEEK.forms.AbstractTextField;
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 AbstractTextField to achieve this. Override the following instance variables like so:
this.field = field;
this.name = 'username';
this.isRequired = true;
this.regex = /([a-zA-Z0-9-\'\s]{8,10})/g
this.cleanRegex = /[^0-9a-zA-Z-\'\s]/g
this.isRequired = true;
this.errorMessage = 'Your username must be between 8 and 10 characters';
this.contextMessage = 'You will use this to login. It must be between 8 and 10 characters';
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);
if(validated) {
// Regex validated, now use AJAX to check if username exists
// On successfull AJAX validation set state to OK - formField.setState(FIELD_STATUS_OK);
// On failure of AJAX validation set state to ERROR - formField.setState(FIELD_STATUS_ERROR);
checkUsername(this.field.value, formField);
} else {
if(this.modified == false) {
this.setState(FIELD_STATUS_INFO);
} else {
this.setState(FIELD_STATUS_ERROR);
}
}
return true;
}
This function is simple yet vital, as it is called automatically by FormFieldFactory and assigns the object returned to be the handler for a particular form field. This assigned is done by matching a class name attribute from a form to a registered class name which we do in step 6.
this.getNewInstance = function(field) {
return new ONEGEEK.forms.UsernameTextField(field);
}
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', new ONEGEEK.forms.UsernameTextField());
Now when you load the page your new function will handle the validation!
Here is the entire code listing for the customisation:
ONEGEEK.forms.UsernameTextField = function(field) {
this.field = field;
this.name = 'username';
this.isRequired = true;
this.regex = /([a-zA-Z0-9-\'\s]{8,10})/g
this.cleanRegex = /[^0-9a-zA-Z-\'\s]/g
this.isRequired = true;
this.errorMessage = 'Your username must be between 8 and 10 characters';
this.contextMessage = 'You will use this to login. It must be between 8 and 10 characters';
this.getNewInstance = function(field) {
return new ONEGEEK.forms.GenericTextField(field);
}
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 - this.setState(FIELD_STATUS_OK);
// On failure of AJAX validation set state to ERROR - this.setState(FIELD_STATUS_ERROR);
checkUsername(this.field.value, this);
} else {
if(this.modified == false) {
this.setState(FIELD_STATUS_INFO);
} else {
this.setState(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', new ONEGEEK.forms.UsernameTextField());
The library has been tested successfully on the following browsers:
| Next > |
|---|