At long last we arrive at what is considered one of the biggest advantages of using JavaScript: the ability to validate forms before they are sent to the originating server. This topic has been mentioned throughout the book but as yet has been explained very little.
Form validation used to occur at the server, after the client had entered all necessary data and then pressed the Submit button. If some of the data that had been entered by the client had been in the wrong form or was simply missing, the server would have to send all the data back to the client and request that the form be resubmitted with correct information. This process used to be long and tedious because of slow transfer speeds, but with the introduction of JavaScript, all validation of form data could be done on the client's computer without any input needed from the server.
Form validation generally performs two functions. First of all, the form must be checked to make sure data was entered into each form field that required it. Secondly, the data that is entered must be checked for correct form and value. The first part is usually trivial—just loop through each field in the form and check for data. It is the second part of form validation that required the most thought. Everything you have learned thus far will play a part in the validation process.
The most common type of form on the Web right now is used to get billing information for an online transaction. Here is an example of such a form with just a basic validation function:
<html> <head> <title> JavaScript Professional Projects - Form Validation </title> <script language="JavaScript"> <!-- function validate() { var good = true; with( document.theForm ) { if( names.value == "" || names.value.indexOf( "," ) < 1 ) { alert( "Please provide your first and" + " last name separated by a comma." ); good = false; } if( address.value == "" ) { alert( "Please provide an address." ); good = false; } if( city.value == "" ) { alert( "Please provide a city." ); good = false; } if( state.value == "" ) { alert( "Please provide a state." ); good = false; } if( zip.value == "" || isNaN( zip.value ) || zip.value.length != 5 ) { alert( "Please provide a zip in the format #####." ); good = false; } } return( good ); } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 8: Form Validation</font> </center> <br><br> <br><br> <table cellspacing="4" cellpadding="4" width="65%"> <tr> <td> <form name="theForm" onSubmit="JavaScript: return( validate() );"> <b><font size="5">Mailing Address</font></b><br> <br> <b>Last name, First name:</b><br> <input type="text" name="names" size="36"><br> <b>Street/Address:</b><br> <input type="text" name="address" size="36"><br> <b>City:</b><br> <input type="text" name="city" size="36"><br> <b>State:<br> </b><input type="text" name="state" size="36"><br> <b>Zip code:</b><br> <input type="text" name="zip" size="36"> <input type="submit" value="Submit"></form> </td> </tr> </table> </body> </html>
This example performs a very basic form validation by checking each form element's value to make sure it conforms to the desired information type. One downfall and annoying feature of this validation function is that it creates an error message for every error that occurs in the page. If the user accidentally hits the Submit button and this form was much longer, he or she would spend the next couple of minutes repeatedly hitting the alert dialog's OK button.
Thankfully, there is a better way to report errors than this:
<html> <head> <title> JavaScript Professional Projects - Form Validation </title> <script language="JavaScript"> <!-- function validate() { try { with( document.theForm ) { if( names.value == "" || names.value.indexOf( "," ) < 1 ) { throw "Please provide your first and" + " last name separated by a comma."; } if( address.value == "" ) { throw "Please provide an address."; } if( city.value == "" ) { throw "Please provide a city."; } if( state.value == "" ) { throw "Please provide a state."; } if( zip.value == "" || isNaN( zip.value ) || zip.value.length != 5 ) { throw "Please provide a zip in the format #####."; } } } catch( error ) { alert( error ); return( false ); } return( true ); } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 8: Form Validation</font> </center> <br><br> <br><br> <table cellspacing="4" cellpadding="4" width="65%"> <tr> <td> <form name="theForm" onSubmit="JavaScript: return( validate() );"> <b><font size="5">Mailing Address</font></b><br> <br> <b>Last name, First name:</b><br> <input type="text" name="names" size="36"><br> <b>Street/Address:</b><br> <input type="text" name="address" size="36"><br> <b>City:</b><br> <input type="text" name="city" size="36"><br> <b>State:<br> </b><input type="text" name="state" size="36"><br> <b>Zip code:</b><br> <input type="text" name="zip" size="36"> <input type="submit" value="Submit"></form> </td> </tr> </table> </body> </html>
Instead of using a flag variable like the previous example, this example uses JavaScript's built-in error catching feature to make sure that only one error message is shown at a time. Unfortunately, this means that for very long forms the user will have to repeatedly hit the Submit button to fix each error. Although this is preferable to getting a cascade of error messages, it still isn't the best approach.
Luckily, there is a way to provide information for each error without presenting the user with multiple alert dialog boxes or forcing him to click on the Submit button repeatedly. Here it is:
<html> <head> <title> JavaScript Professional Projects - Form Validation </title> <style type="text/css"> <!-- .message{ position: absolute; visibility: hidden; } --> </style> <script language="JavaScript"> <!-- function validate() { var good = false; if( navigator.appName == "Netscape" ) { with( document.theForm ) { if( names.value == "" || names.value.indexOf( "," ) < 1 ) { alert( "Please provide your first and" + " last name separated by a comma." ); good = false; } else if( address.value == "" ) { alert( "Please provide an address." ); good = false; } else if( city.value == "" ) { alert( "Please provide a city." ); good = false; } else if( state.value == "" ) { alert( "Please provide a state." ); good = false; } else if( zip.value == "" || isNaN( zip.value ) || zip.value.length != 5 ) { alert( "Please provide a zip in the format #####." ); good = false; } } } else { with( document.theForm ) { if( names.value == "" || names.value.indexOf( "," ) < 1 ) { with( document.all.namesMessage.style ) { position = "relative"; visibility = "visible"; } good = false; } else { with( document.all.namesMessage.style ) { position = "absolute"; visibility = "hidden"; } } if( address.value == "" ) { with( document.all.addressMessage.style ) { position = "relative"; visibility = "visible"; } good = false; } else { with( document.all.addressMessage.style ) { position = "absolute"; visibility = "hidden"; } } if( city.value == "" ) { with( document.all.cityMessage.style ) { position = "relative"; visibility = "visible"; } good = false; } else { with( document.all.cityMessage.style ) { position = "absolute"; visibility = "hidden"; } } if( state.value == "" ) { with( document.all.stateMessage.style ) { position = "relative"; visibility = "visible"; } good = false; } else { with( document.all.stateMessage.style ) { position = "absolute"; visibility = "hidden"; } } if( zip.value == "" || isNaN( zip.value ) || zip.value.length != 5 ) { with( document.all.zipMessage.style ) { position = "relative"; visibility = "visible"; } good = false; } else { with( document.all.zipMessage.style ) { position = "absolute"; visibility = "hidden"; } } } } return( good ); } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 8: Form Validation</font> </center> <br><br> <br><br> <table cellspacing="4" cellpadding="4" width="65%"> <tr> <td> <form name="theForm" onSubmit="JavaScript: return( validate );"> <b><font size="5">Mailing Address</font></b><br> <br> <b>Last name, First name:</b><br> <div id="namesMessage" class="message"> <font color=red>Please provide your first and last name separated by a comma.</font> </div> <input type="text" name="names" size="36"><br> <b>Street/Address:</b><br> <div id="addressMessage" class="message"> <font color=red>Please provide an address.</font> </div> <input type="text" name="address" size="36"><br> <b>City:</b><br> <div id="cityMessage" class="message"> <font color=red>Please provide a city.</font> </div> <input type="text" name="city" size="36"><br> <b>State:</b><br> <div id="stateMessage" class="message"> <font color=red>Please provide a state.</font> </div> <input type="text" name="state" size="36"><br> <b>Zip code:</b><br> <div id="zipMessage" class="message"> <font color=red>Please provide an zip in the format #####.</font> </div> <input type="text" name="zip" size="36"> <input type="submit" value="Submit"></form> </td> </tr> </table> </body> </html>
This example hides DIV elements with error messages in them above each form field. If the user tries to submit incorrect data, the DIV elements will be shown for each form field containing the erroneous data. This technique not only provides feedback for each error, but it does so right on the screen. The drawback to this method is that it only works effectively in Internet Explorer, so if you're doing error checking outside of a controlled environment like an intranet, you may wish to use one of the alternative ways to report the errors described above.
The above example, in order to fully demonstrate the concept, was really longer than it needed to be. The function validate() could have been written like this:
function validate() { var good = false; if( navigator.appName == "Netscape" ) { with( document.theForm ) { if( !( good = !(names.value == "" || names.value.indexOf( "," ) < 1)) ) alert( "Please provide your first and" + " last name separated by a comma." ); else if( !(good = !(address.value == "")) ) alert( "Please provide an address." ); else if( !( good = !(city.value == "")) ) alert( "Please provide a city." ); else if( !( good = !(state.value == "")) ) alert( "Please provide a state." ); else if( !( good = !(zip.value == "" || isNaN( zip.value ) || zip.value.length != 5)) ) alert( "Please provide a zip in the format #####." ); } } else { with( document.theForm ) { var flag = names.value == "" || names.value.indexOf( "," ) < 1; with( document.all.namesMessage.style ) { position = ( flag ? "relative" : "absolute" ); visibility = ( flag ? "visible" : "hidden" ); } if( !flag ) good = false; flag = address.value == ""; with( document.all.addressMessage.style ) { position = ( flag ? "relative" : "absolute" ); visibility = ( flag ? "visible" : "hidden" ); } if( !flag ) good = false; flag = city.value == ""; with( document.all.cityMessage.style ) { position = ( flag ? "relative" : "absolute" ); visibility = ( flag ? "visible" : "hidden" ); } if( !flag ) good = false; flag = state.value == ""; with( document.all.stateMessage.style ) { position = ( flag ? "relative" : "absolute" ); visibility = ( flag ? "visible" : "hidden" ); } if( !flag ) good = false; flag = zip.value == "" || isNaN( zip.value ) || zip.value.length != 5; with( document.all.zipMessage.style ) { position = ( flag ? "relative" : "absolute" ); visibility = ( flag ? "visible" : "hidden" ); } if( !flag ) good = false; } } return( good );
This example is a much shorter (albeit harder-to-read) version of the previous example. If you're worried about download time for your page, then use the second version instead of the first, as it reduces the number of characters needed to download from 1627 to 1410.
There are far too many ways to validate a form to present in the limited space of this book. I encourage you to visit professional Web sites that use forms in order to find new and better techniques of form validation.