Sunday, 31 January 2010
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 required" />
<input type="text" name="lastname" class="lastname required" id="lastname"/>
<input type="text" name="subject" class="text required" id="subject" />
<input type="text" name="captcha" class="captcha required" id="captcha" />
<input type="text" name="phone" class="phone required" id="phone"/>
<input id="submit" type="submit"/>
</form>
There are a few things to notice here;
There are 4 examples, ranging from simple to advanced implementation:
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 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 |
| } | ||
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:
By implementing the library in this way, we allow for simple extensibility by implementing subclasses at the lowest level.
Read the JavaScript API or download it from Google Code.

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.
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:
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.
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',
...
}
};
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)
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)';
}
}
};
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: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!"
};
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:
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 ONEGEEK.forms.AbstractTextField.
ONEGEEK.forms.UsernameTextField = function(field) {
this.field = 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 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';
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
// 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;
}
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!
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';
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');
The library has been tested successfully on the following browsers on Windows:
and the following browsers on Linux:
| < Prev | Next > |
|---|