Copyright (c) 2001, 2002, 2003, 2004, Paul Strack.
This document describes an open source JavaScript form
validation library: FormValidation.js
. The document is
broken down into the following sections:
formdata
Objectformitems
ArrayThe purpose of this library is to support complex validations of HTML form values via JavaScript. In practice, there are a number of issues surrounding JavaScript form validation:
textField.value
vs.
selectList.selectedIndex
.This library attempts to address these issues by standardizing and automating as much form validation process as possible. The library's functionality rests on two key objects:
validations
: An object that holds
validation information for the entire form.formdata
: An object with simple
getter/setter methods for manipulating form data.Common Validation Operations: The page developer
specifies the properties of the validations
object
(validation properties) to control how individual fields in
the form are validated. The validation properties are used during
the page's onload
event to initialize form and field
validation functions. For example, to mark a field as required, the
developer simply sets: validations.field.required =
true
.
Validation Event Handlers: This library automatically
assigns validation functions to the appropriate event handlers of
form elements: onchange
for text elements,
onchange/onblur
for select lists, onclick
for radio buttons and checkboxes and onsubmit
for the
form itself. The web developer does not need to assign any form
element event handlers.
Getting and Setting Field Values: The
formdata
object's methods can be used to manipulate
field data. The formdata
object has
getField()
and setField()
methods for every field. If a form has an "address
"
field, it can be manipulated via get/setAddress()
methods. Furthermore, the getField()
method
parses the field value to a specified data type and the
setField()
method formats the value as
appropriate when assigning it to the field. Typically, the
formdata
object is used to write custom validation
methods.
This library should function correctly for all 4th generation or later browsers: Netscape Navigator 4.0+ and Internet Explorer 4.0+. It should also work in any other web browser that complies with the ECMA v1 JavaScript standard. This library is open source, using a BSD-style license. See the Form Validation Library License for more details.
To use this library's functions and objects, you must (a) import
the library's .js
file and (b) call the library's
initFormValidation()
method during the page's
onload
event:
<script
src="FormValidation.js"></script> |
If the library is not located in the same directory as the form
itself, you must use the correct path to the library in the
script's src
attribute. If the page needs additional
initialization during the page's onload
event, simply
call the library's initFormValidation()
method from
within the page's init()
function:
<script> |
Another alternative is to assign the
initFormValidation()
method to the
onfocus
event of every field:
<script
src="FormValidation.js"></script> |
If you use this onfocus
event technique, you must
make sure that it is applied to every form element, otherwise the
form will not be initialized if the user interacts with that
element first. This alternative may seem like a poor approach, but
it works well if the form elements are generated by some sort of
server-side scripting.
In order for the library to function correctly, the HTML form must obey the following rules:
name
attributes must be
valid JavaScript variable names (that is, without spaces or special
characters).form
object: action
,
elements
,encoding
,length
,
method
,name
,onreset
,onsubmit
,
reset
,submit
,target
.name
attribute.name
attribute per group of radio buttons.<select multiple>
tags. (This needs to be addressed in the future).The rule for unique element names may be broken under
specialized circumstances, if the repeated form elements are
arranged in groups of related fields. See the section on
the formitems
array
for additional details.
This validation library supports simple declarations for the following common single-field validations:
All of these common validations must be assigned to the
validations
object as validation properties.
Before this can be done, a new Validator
object for
the field must be created and assigned as a
validations
object. It must be assigned to a property
whose name matches the field to be validated:
validations.field = new Validator("Field
Label"); |
Once a Validator
object has been created for the
field, the validation properties for that field can be
assigned to it. A complete list of possible validation properties
is given below. Not every field will have every property:
<script> |
Form elements groups which all have the same name (such as radio buttons) only need a single validation object and set of validation properties.
<script> |
A field should only have the validation properties appropriate
to that field. For example, suppose a loginForm
has a userID
field that is required and must be
between 6 and 10 characters in length. It would have the following
validation properties:
User ID: <input type="text"
name="userID"> userID
.required = true; userID
.minlength = 6; userID
.maxlength = 10; |
The field validation properties must be defined in the page
after the FormValidation.js
library is
imported. The best place to define field validation properties is
either (a) immediately after each field or (b) in one big block at
the end of the HTML page.
The parameter for the Validator
constructor is the
human-readable label for the field, used for generating error
messages. The form's initialization copies validation properties
from the validations
object to the corresponding form
elements. In addition, it creates and assigns a label
property to the element whose value matches the parameter of the
Validator
constructor.
// After form initialization: |
The meaning of each validation properties is as follows:
label
: The human-readable label for the
field, used for generating error messages. If the field has any
validation properties, it will also have a label
property, whose value matches the parameter of the
Validator
constructor.readonly
: Whether the field is read-only.
If the user attempts to enter data into a read-only field, the
cursor will move to the next field that is not read-only.required
: Whether the field is required. If
the value for any required fields is blank, an error message will
be generated when a form is submitted.max, min
: The upper and lower bounds for
the numeric values of the field. The field may have just a
max
, just a min
or both. The
max
and min
are themselves included in
the range of allowed values. These values are only meaningful for
numeric fields (including currency).maxlength, minlength
: The upper and lower
bounds for the length of the text in the field. The field may have
just a maxlength
, just a minlength
or
both. The maxlength
and minlength
are
included in the range of allowed lengths.datatype
, scale
: These
properties relate to field data types for formatting and parsing,
and are described in the detail in Field
Data Types section.compute
: This property allows the
assignment of custom validation functions to handle more complex
computations and validations. It is described in the detail in
Custom Validations
section.Field formatting and parsing may be specified through the
field's datatype
validation properties The name
"datatype
" is used rather than "type
" to
better distinguish it from the HTML/JavaScript type
attribute used to designate the type of a form input element
("text
", "checkbox
", etc.). Each data
type has formatting and parsing functions associated with, which
are used to manage field values. The appropriate formatting and
parsing functions are assigned as methods to the field based on the
field's datatype
. For example, an
itemAmount
field in an orderForm
might
use the "Integer
" data type to ensure that the field
only holds numeric values:
Amount: <input type="text" name="itemAmount"> |
The form validation library has the following predefined data types:
"Integer"
: A positive integer value."SignedInteger"
: A signed integer
value."Decimal"
: A positive decimal value."SignedDecimal"
: A signed decimal
value."Currency"
: A positive currency amount
($##,###.##
)."SignedCurrency"
: A currency value,
allowing negative amounts."Phone"
: A phone number
(###-###-####
)."SSN"
: A social security number
(###-##-####
)."Postal"
: A postal code (#####
or #####-####
)."Email"
: An email address (for example,
name@domain.com
)."Date"
: A date value
(mm/dd/yyyy
).JavaScript developers can define new data types simply by
creating appropriate formatType
and
parseType
functions for the new type. Consult
the existing formatting and parsing functions for examples. Each
field will be assigned the formatting and parsing functions
appropriate to the field's datatype
. For example,
fields with a datatype
of "Integer
" will
be assigned the formatInteger()
and
parseInteger()
functions.
Field formatting is called as part of both field and form validation. Field formatting appropriate to the data type occurs automatically, but not until after the user finishes entering the text and attempts to move to the next field in the form. If the contents of the field cannot be changed to the correct format, an error message alert is generated.
Field parsing is used when field values are needed in
calculations within other scripts on the page. Ordinarily, values
retrieved from a form field are strings. If a field holds a numeric
or date data type, the appropriate parse
method is
used to retrieve values of a more appropriate JavaScript type
(number
, Date
, etc.). If for some reason
parsing fails, the parse methods return a value of NaN
(JavaScript's Not-A-Number value). The NaN
value is
returned for unparseable dates as well as numbers.
Finally, there is an additional validation property only used by decimal fields:
scale
: The number of places after the
decimal point. Currency fields automatically have a
scale
of 2.For example, a decimal field with a scale of 3 will always be
formatted #.###
. Missing values are filled with 0's.
Excess values are rounded.
formdata
ObjectThe library's form initialization assigns
getValue()
and setValue()
methods to each
form element. These methods hide the differences between the data
manipulation mechanisms of different field types. The methods may
be called as follows:
var value =
document.form.field.getValue(); |
The library also generates a global formdata
object
that allows the developer to manipulate form field values using
simple getField()
and
setField()
methods. For example, if a form has
an "address
" field, it can be accessed via
formdata.getAddress()
and
formdata.setAddress(value)
methods. The methods of the
formdata
object are:
getField()
: Returns the field's value,
parsed if appropriate.setField(value)
: Sets the field's value,
formatting it if appropriate.getFieldText()
: Returns the field's text
(select lists only).computeField()
: Calls the field's
compute
method for calculations and multi-field
validations.In each case, Field
is replaced by the
field's name, with the first letter capitalized. The last two
methods are only present if the field has a matching method of the
appropriate type (getText
and compute
).
Each method can be called through the global formdata
object. For example, the following pairs of method calls are
roughly equivalent:
formdata.setField(value); |
The above method calls are only identical if the field is not
assigned a data type. If the field has a data type with a
parse
method, then the getField()
method will return the parsed value (such as a number or date),
while the field.getValue()
method the returns
the actual field value as an unparsed string. If the field has a
data type with a format
method, than the
setField()
method will format the field's value
while setting it, while the field.setValue()
will not.
As an example, consider the simple form:
|
It's HTML is:
<table> |
It will have the following formdata
methods:
getUserID()
: Returns the userID
field's value.setUserID()
: Sets the userID
field's
value.getPassword()
: Returns the password
field's value.setPassword()
: Sets the password
field's value.getAccess()
: Returns the access
list's value.getAccessText()
: Returns the access
list's text.setAccess()
: Sets the access
list's
value.The statement formdata.setAccess("E")
would select
the "Employee" option, and formdata.getUserID()
would
return the current contents of the userID
field. The
formdata
methods can be used when writing custom
validation functions:
<script> |
No generic library can cover all possible field validations.
This library allows JavaScript developers to define custom
computations and validations, both for individual fields and for
the form as a whole. These custom validation methods are assigned
to the compute
method of the field's validations
object. This compute
method will be called along with
the other validation methods when the element's event handler is
triggered (onchange
,
onblur
,onclick
or onsubmit
,
depending on the field type).
<script> |
A custom compute
method should:
The method should return an empty string (""
) if
everything goes well or a string with an error message if the field
is invalid. Any error string should end in "\n\n"
, so
that it display nicely within lists of errors. The
compute
method can be defined with any name, but for
consistency should be in the form computeXxx
.
If written correctly, the same custom compute
method
can be used for multiple fields:
<script> compute
=
computeIDforAccess
; compute
=
computeIDforAccess
; |
When the form is submitted, it calls the compute
methods for every field in the form one last time before
submission. Under some circumstances, this may lead to extraneous
error messages. To avoid this problem, you may also define a global
compute
method for the form itself. If the form has a
compute
method, the compute
methods for
individual fields will not be called when the form is
submitted.
<script> |
To write more generic compute
methods, you can use
the getValue()
and setValue()
methods of
the field itself. Since the compute
method is assigned
as a method of the field, you can access these getter and setter
methods via this.getValue()
and
this.setValue()
. Similarly, you can use other field
validation properties and methods like label
and
parse()
. If properly written, such
compute
methods can be assigned to any field in any
form.
<script> |
Finally, compute
methods can be used to update
other fields whose values need to change when the given field's
value changes. When writing such custom computations, it is
especially helpful that the getField()
methods
of the formdata
object will return the parsed value
and the setField()
methods will format the
field's value while setting it.
In the following example, the computeTaxes()
of the
total
field will automatically update the
tax
field. Every compute
method must
return a string value, so it should return an empty string if no
errors are possible.
<script> |
When writing custom validations, be sure to consider the following:
compute
method is called after the
format
method, which mitigates (but does not
eliminate) formatting issues.formdata.setField()
method does not
automatically trigger its compute
method. This is
deliberate, to avoid endless loops.formitems
ArrayThe form may have elements with the same name (other than radio
buttons) under specialized circumstances. In particular, the
elements must be arranged in repeated sets of related elements.
Under these circumstances, the library will initialize a
formitems
array. The entries in this array will have
get/setField
methods for the form field
sets.
For example, consider this form:
|
It's HTML is:
<table> itemsCost
"></td> |
The items in the formitems
array will have these
methods:
getItemName()
: Returns the itemName
field's value.setItemName()
: Sets the itemName
field's value.getCostPerItem()
: Returns the
costPerItem
field's value.setCostPerItem()
: Sets the
costPerItem
field's value.getAmount()
: Returns the
a
mount
field's value.setAmount()
: Sets the
a
mount
field's value.getItemsCost()
: Returns the itemsCost
value.setItemsCost()
: Sets the itemsCost
value.These get/set
methods with parse and format the
specified fields, as appropriate. Like radio buttons, the
validation properties for the repeated fields only need to be
assigned once. The validations for this form might look like:
<script> itemName= new
Validator("Item Name"); costPerItem=
new Validator("Cost per Item"); costPerItem.datatype
= "Currency"; costPerItem.compute
= computeTotals; amount
= new Validator("Item Amount"); amount
.datatype = "Integer"; amount.compute
= computeTotals; itemsCost=
new Validator("Cost for All Items"); itemsCost.readonly
= true; itemsCost.datatype
= "Currency"; |
A combination of the formdata
object and the
formitems
arrays can be used to write the
computeTotals
custom validation method.
<script>
formitems [i].getCostPerItem();
formitems [i].getAmount();
formitems[i].setItemsCost("");
[i].setItemsCost(costPerItem *
amount); formdata.getTaxRate();
formdata .setTotal(subtotal
* taxRate); |
In practice, this form would likely be dynamically generated
with a variable number of (possibly pre-populated) item fields. The
computeTotals()
function accommodates these
variations.
Internationalization: This validation library is prepared
for internationalization. To localize the library to a non-US,
non-English region, create an extra validation library for the new
locale. The name for this localized library should follow the usual
internationalization naming conventions, such as
FormValidation_sp_ES.js
for Spanish localized to Spain
or FormValidation_en_GB.js
for English localized to
Great Britain. The localized library should have localized
variations the following items in the core library:
PHONE_ERROR
,
EMAIL_ERROR
,POSTAL_ERROR
, etc.)formatPostal
and parseDate
.The localized variants should have the exact same names as the original message string variables and formatting/parsing functions. To localize a given HTML page, import the locale-specific library after the core library:
<script
src="FormValidation.js"></script> |
The locale-specific error messages and functions will then
replace the US-English language messages and functions. This
localization should be relatively simple for dynamically generated
HTML pages, where the correct localization can be inserted into the
page based on the user's preferences. Note that the library's
internationalization only covers error messages generated by common
validations. Field labels, customized compute
validation methods and the page's content will have to be
internationalized and localized by the web developer.
Validation Script Generation: In well-designed systems, HTML forms will be dynamically generated by a server-side process using some business object framework. In that case, it should be possible to programmatically determine the correct validations for each field by using the characteristics of the corresponding business objects. The server-side process could then dynamically generate the validation JavaScript along with rest of the HTML form, for the common validations at least.
Automatic script generation can speed development time as well as reducing errors and maintenance cost. The exact code necessary for such script generation depends on both the server-side process used for HTML generation (ASP, JSP, PHP) and the business object framework using to support the business logic.
Form Submission with JavaScript Buttons: In Internet
Explorer, when the page focus is in any text element, hitting the
[Enter] key will submit the form. To circumvent the problems that
arise from the accidental submission of complex forms, many web
developers create HTML forms that have no input element of type
"submit"
. Instead, they create a JavaScript button
that fulfills the same function:
<input type="button" value="submit" |
Unfortunately, such a button will circumvent the
onsubmit
event of the form, skipping the library's
form validation. Here is a JavaScript button that will both
validate and submit the form:
<input type="button" value="submit" |
This documentation includes a few additional references:
In addition, here are several example page's demonstrating the library's use:
This library is a good example of the Facade design pattern,
namely a single object (formdata
) that provides
simplified access to a host of other objects (all the objects
representing field elements). It makes extensive use of one of the
interesting capabilities of the JavaScript language: the ability to
define new methods dynamically and assign them to objects. This
allows the library to inspect the characteristics of the form at
runtime and dynamically create the formdata
facade.
This library uses a custom error handling mechanism: returning string values which are either empty (indicating no error) or are non-empty, containing an error message. This custom error handling mechanism is used rather than the standard error handling of JavaScript 1.5 for backwards compatibility with older browsers.