This document provides an overview about the best practices for client side form validation in JavaScript.
The recommendations made throughout this document are a collection of those given in EFnet's #javascript channel.
In this overview, we want the user to fill out the following form:
<form action="update.aspx" method="post">
<p>
<label for="fname">First Name</label>
<input id="fname" name="name">
<label for="lname">Last Name</label>
<input id="lname" name="name">
<label for="email">Email</label>
<input id="email" name="email">
<button type="submit">Save</button>
</p>
</form>
As all fields are required, the script on the server returns the user to the form if one or more of the fields are empty. This is not very responsetive for the user (obviously, the post and reload of the forms page take some time and if the server is under heavy load the response time increases).
So, to improve the responsiveness of the form and to reduce the load on the server we want to add client side form validation.
Note: client side validation is not a replacement for server side validation, only a tool to improve user experience. You should always validate user input on the server.
For this overview we will validate the form data when the user submits the form. Luckily the W3C board in charge for the HTML specification added an event which we can use to execute the validation code: onsubmit
. With this event the form now looks like:
<form action="update.aspx" method="post" onsubmit="validateForm();">
validateForm()
is the validation function which is defined laterBut we want to stop the submit of the form if some of the fields are not filled in. So, as events are stopped if the event handler code returns false
, we change the onsubmit
to:
<form action="update.aspx" method="post" onsubmit="return validateForm();">
To simplify the access to the form fields in the validation function we pass the forms object to the function:
<form action="update.aspx" method="post" onsubmit="return validateForm(this);">
Now that we modified the form to execute the validation code when the user submits the form, we need to implement the actual validation code.
function validateForm(form) {
var isValid = true;
// Validation code here
return isValid;
}
As noted above, we simply want to ensure that the user fills in all fields. Adding the code to check the length of the fields values results in:
function validateForm(form) {
var isValid = true;
var msg = "The following field(s) need to be filled in:\n";
// Check each field individually
if(form.fname.value.length == 0) {
msg += "\tFirst Name\n";
isValid = false;
}
if(form.lname.value.length == 0) {
msg += "\tLast Name\n";
isValid = false;
}
if(form.email.value.length == 0) {
msg += "\tEmail\n";
isValid = false;
}
// Show the error message to the user
if(!isValid) alert(msg);
return isValid;
}
The onsubmit
event of the form provides a nice and easy way to validate form field data. Passing the form object to the validation function simplifies form field access. This introduction shows only the tip of the iceberg of possibilities available to do client side form validation. To name a few:
Validate the form fields onblur
or onchange
giving immediate feedback (should not be done through alert
s) if the input is considered valide or not.
Disable the submit button until the input is considered valid (requires the previous).
Provide additional hints on what the user should enter into the field.
Generic form validation.
Some of these may be covered in a future article.
Giving the submit button the name submit is a Bad Idea™. Reason: because of legacy browser behaviour the name of the submit button will override the methods of the form object disabling the ability to submit the form via script (even though script submitting should be a last resort only).
Form field elements that share a name (e.g. radio buttons) form.sharedName
returns a collection.
// rds is a reference to the radio buttons, e.g. var rds = form.nameSharedByRadioButtons;
for(var i = 0; i < rds.length; i++)
if(rds[i].checked) break;
// if i equals the length of the collection, no radio button is selected
if(i == rds.length) {
isValid = false;
alert("Please select an option");
}
See PHP and SELECT naming conflicts for an indeep discussion (ignore the spec quote) of this issue.
To validate the form based on the used submit button these options are possible:
Setting a flag in the onclick
event of the submit button that determines the code path to be used during validation:
var validateFor = 0;
function validateForm(form) {
if(validateFor == 0) {
// validate the form for saving
} else if(validateFor == 1) {
// validate the form for deletion
}
}
<form onsubmit="return validateForm(this);">
<button type="submit" onclick="validateFor = 0;">Save</button>
<button type="submit" onclick="validateFor = 1;">Delete</button>
useValFunc
is a global variable that determines the validation code path to be usedUse a function reference in the onsubmit
handler of the form and change it in the onclick
event of the submit button to reference the wanted validation function:
function validateSave(form) {
// validate the form for saving
}
function validateDelete(form) {
// validate the form for deletion
}
var validateForm = validateSave;
<form onsubmit="return validateForm(this);">
<button type="submit" onclick="validateForm = validateSave;">Save</button>
<button type="submit" onclick="validateForm = validateDelete;">Delete</button>