Simple but powerful JQuery Form Validation

I wrote a relatively simple and intuitive form validation script for a client, which they kindly allowed me to release into the open-source community.

Contents

The Objective
The Basics
Including The JavaScript
Explaining The Code
Core Functions
Expanded Functions
Options
HTML
Examples
Download
License
To-Do’s
Change-log

The Objective

The aim was to develop a simple JavaScript form validator plugin to be:

  • JQuery based
  • Fast and efficient
  • Automated (via CSS Classes)
  • Adjustable (via option settings)
  • Easily expandable

The Basics

From a simplistic overview, the plugin loops around any form with a submit button and validates input elements based on its CSS classes.
The standard CSS classes it works on are:
required – if an input is marked as ‘required’ it simply makes sure the field is not empty.
email – it does a simple regex check to ensure the format is correct.
digit – it checks whether the field only contains numbers 0 to 9.
alpha – checks if the field contains characters a to z and A to Z.

Including the JavaScript

First include JQuery, supports 1.3.2 – 1.4.2:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

Then include our script:

<script type="text/javascript" src="options.validate-form.js"></script>
<script type="text/javascript" src="validate-form.js"></script>

Explaining the Code

Attaching the code automatically to all Forms is carried out by:

$().ready(function() {
	//attach plugin to all forms with a submit button (except for ignored forms)
	$('form:not('+ formsToIgnore() +')').submit(function() {
		var formId = $(this).attr('id');
		var matchingElements = $('form#'+ formId +' input[type=text], form#'+ formId +' textarea, form#'+ formId +' input[type=checkbox]');
		if (!matchingElements == "") {
			var formError = validateForm(formId, matchingElements);
			if (formError == true) {
				return false
			} else {
				return true;
			}
		}
	});
});

If you need eager validation (it annoys me, but some people seem to love it #shake-head), set the options variable eagerValidation=true (see script options or examples), or if you don’t need it, remove it.

//check whether to eagerly validate each field
	if (eagerValidation == true) {
		$('form input[type=text], form textarea, form input[type=checkbox]').focusout(function() {
			var fieldId = $(this).attr('id');
			var formId = $('#'+fieldId).parents('form').attr('id');
			if (validateField(formId, fieldId) == false) {
				removeFieldError(formId, fieldId);
			}
			removeFormError(formId);
			addFormError(formId);
		});
	}

Core Functions

function validateField(formId, fieldId) {
	if (fieldId) {
		removeFieldError(formId, fieldId);

		var element = buildElement(formId, fieldId);
		var fieldValue = jQuery.trim(jQuery(element).val());
		var fieldLength = fieldValue.length;
		var fieldErrorMessage = "";

		if ($(element).hasClass('text')) {
			if ($(element).hasClass('alpha') && fieldLength > 0) { // from string start to end, only contains '-' "whitespace" or 'aA'-'zZ'
				if (validateAlpha(fieldValue) == false) {
					fieldErrorMessage = alphaFieldError;
				}
			} else if ($(element).hasClass('digit') && fieldLength > 0) {
				if (validateDigit(fieldValue) == false) {
					fieldErrorMessage = digitFieldError;
				}
			} else if ($(element).hasClass('email') && fieldLength > 0) {
				if (validateEmail(fieldValue) == false) {
					fieldErrorMessage = emailFieldError;
				}
			} else if ($(element).hasClass('required') && fieldLength == 0) {
				fieldErrorMessage = requiredTextError;
			}
		} else if ($(element).is('.textarea.required') && fieldLength == 0) {
			fieldErrorMessage = requiredTextareaError;
		} else if ($(element).is('.checkbox.required') && !$(element).is(':checked')) {
			fieldErrorMessage = requiredCheckboxError;
		}

		if (!fieldErrorMessage) {
			return false;
		} else {
			if (customErrorSelectors.length > 0) {
				for (i=0;i<customErrorSelectors.length;i++) { //check for overrides
					if (customErrorSelectors[i] == element) {
						fieldErrorMessage = customErrorMessages[i];
					}
				}
			}
			addFieldError(formId, fieldId, fieldErrorMessage);
			return true;
		}
	}
}

function validateForm(formId, matchingElements) {
	removeAllErrors(formId);

	matchingElements.each(function(index) {
		var elementId = $(this).attr('id');
		var fieldErrorStatus = validateField(formId, elementId);
	});

	if (countFormErrors(formId) > 0) {
		if (focusFirstError == true) {
			focusOnFirstError(formId);
		}
		if (errorSummary == true) {
			addFormError(formId);
		}
		return true;
	} else {
		if (errorSummary == true) {
			removeFormError(formId);
		}
		return false;
	}
}

Expanded Functions

function buildElement(formId, fieldId) {
	var element = "form#"+formId+" #"+fieldId;
	return element;
}

function focusOnFirstError(formId) {
	$('form#'+formId+' input.'+inputErrorClass+':first').focus();
}

function formsToIgnore() { //check for forms to ignore
	var formIgnoreItems = "";
	for (i=0;i<ignoreForms.length;i++) {
		if (i>0) {
			formIgnoreItems += ", ";
		}
		formIgnoreItems += ignoreForms[i];
	}
	return formIgnoreItems;
}

function countFormErrors(formId) {
	var errorCounter = $('form#'+formId+' '+inputWrapper+'.'+inputWrapperErrorClass).size();
	return errorCounter;
}

function addFormError(formId) {
	var formSelector = 'form#'+formId;
	var errorMessageSelector = formSelector+' p.error-summary';
	var errorCounter = countFormErrors(formId);
	if (errorCounter > 0) {
		if ($(errorMessageSelector).length) {
			$(errorMessageSelector).html(errorCounter + ' field(s) are invalid.');
		} else {
			$(formSelector).prepend('<p class=\"error-summary\">' + errorCounter + ' field(s) are invalid.</p>');
		}
	}
}

function removeAllErrors(formId) {
	removeFormError(formId);
	removeAllFieldErrors(formId);
}

function removeFormError(formId) {
	$('form#'+formId+' p.error-summary').remove();
}

function removeAllFieldErrors(formId) {
	var formSelector = 'form#'+formId;
	$(formSelector+' '+inputWrapper).removeClass(inputWrapperErrorClass);
	$(formSelector+' input[type=text], '+formSelector+' textarea, '+formSelector+' input[type=checkbox]').removeClass(inputErrorClass);
	$(formSelector+' '+inputWrapper+' p.error-message').remove();
}

function addFieldError(formId, fieldId, fieldErrorMessage) {
	var element = buildElement(formId, fieldId);
	$(element).addClass(inputErrorClass)
			  .parents(inputWrapper).addClass(inputWrapperErrorClass)
									.append('<p class=\"error-message\">>' + fieldErrorMessage + '</p>');
}

function removeFieldError(formId, fieldId) {
	var element = buildElement(formId, fieldId);
	$(element).removeClass(inputErrorClass)
			  .parents(inputWrapper).removeClass(inputWrapperErrorClass);
	$(element).parents(inputWrapper).children('p.error-message').remove();
}

function validateAlpha(alpha) {
	var regex = /^[-\sa-zA-Z]+$/
	return regex.test(alpha);
}

function validateDigit(digit) {
	var regex = /^[0-9]+$/
	return regex.test(digit);
}

function validateEmail(email) {
	var regex = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
	return regex.test(email);
}

Options

//Validator options
var eagerValidation = false; //true/false   if set to true, form will eagerly validate each field. False will validate only ever on form submission
var errorSummary = true; //true/false    if set to true will show error summary at the top of the form
var focusFirstError = true; //true/false    if set to true will refocus user input to first error field on form submission
var inputErrorClass = "error";    //set the class name that will be appended to the form input/textarea when an error is detected
var inputWrapper = "p";    //set the element type that is used to wrap the form input/textarea in your forms
var inputWrapperErrorClass = "err";    //set the class name that will be appended to the wrapper of the input/textarea when an error is detected

//Error Messages
var requiredTextError = "cannot be empty"; //Textbox error
var requiredTextareaError = "cannot be empty"; //Textarea error
var requiredCheckboxError = "needs to be ticked"; //Checkbox error
var alphaFieldError = "characters only, no numbers"; //Alpha Textbox error
var digitFieldError = "numbers only, no characters"; //Numeric Textbox error
var emailFieldError = "valid email address only"; //email Textbox error

var ignoreForms = ['#search-form']; //add any forms you need want the form to ignore, e.g search forms, etc. This can be ignored as long as none of the form inputs have 'required' or other validation classes attached

var customErrorSelectors = ['form#testform #el_0','form#testform #el_2']; //include form Id and element Id!
var customErrorMessages = ['this is an error message override, as specified in the config options','this is another error message override']; //Relates directly to customErrorSelectors

HTML

The script assumes an element wrapper is used, and must be included in the options under inputWrapper, the default is <p>. See the examples included for the structure of HTML compatible.

Examples

Simple Example
More Complex Example

Download

Options script – required for validation script to work

Download everything in 1 zipped package

License

Released under MIT License.

To Do’s

  • Improve the efficiency of the code execution.
  • Add min-length class options for fields.

Change-log

2010/05/20: v0.2 released

blog comments powered by Disqus