[ Team LiB ] Previous Section Next Section

8.3 Preventing Form Submission upon Validation Failure

NN 2, IE 3

8.3.1 Problem

You want a validation function that detects incorrect data entry to halt the submission of the form until the user corrects the data entry.

8.3.2 Solution

Batch validation checking typically operates from the onsubmit event handler of the form element. Submission is aborted if the event handler evaluates to return false. Include the return statement in the event handler assignment, and let the validation function supply the Boolean value based on its findings:

<form ... onsubmit="return validateForm(this)">

8.3.3 Discussion

You can implement batch validation by way of a master function that calls the individual validation functions as needed. To demonstrate, let's create a small form with numerous control types in it. Text fields execute real-time validation, while the form's onsubmit event handler performs the batch validation. Both validation types use the validation functions shown in Recipe 8.2 (either the string parsing or regular expression varieties). Here's the form's HTML:

<form method="GET" action="cgi-bin/register.pl"
    name="sampleForm" onsubmit="return validateForm(this)">
First Name: <input type="text" size="30" name="name1" id="name1" 
    onchange="isNotEmpty(this)" /><br>
Last Name: <input type="text" size="30" name="name2" id="name2" 
    onchange="isNotEmpty(this)" /><br>
Email Address: <input type="text" size="30" name="eMail" id="eMail" 
    onchange="if (isNotEmpty(this)) {isEMailAddr(this)}" /><br>
Your Region: <select name="continent" id="continent">
    <option value="" selected>Choose One:</option>
    <option value="Africa">Africa</option>
    <option value="Asia">Asia</option>
    <option value="Australia">Australia/Pacific</option>
    <option value="Europe">Europe</option>
    <option value="North America">North America</option>
    <option value="South America">South America</option>
</select><br>
Licensing Terms: 
    <input type="radio" name="accept" id="accept1" value="agree" />I agree
    <input type="radio" name="accept" id="accept2" value="refuse" />I do not agree
<br>
<input type="reset" /> <input type="submit" />
</form>

You can see the form in Figure 8-1. As the user tabs and clicks through the form, typically the only validation taking place is in the email text box. Tabbing through the empty name fields without making any changes won't trigger the onchange event handlers there (another reason why batch validation is needed). In this form, we also want to make sure that a choice is made from a select element, and that a member of the radio button group is clicked (some designers might question delivering radio buttons without a default selection, but this example requires no initial selection).

Figure 8-1. A form of mixed input types
figs/jsdc_0801.gif

When the user clicks the Submit button, the validateForm( ) function executes to perform validations of all required form controls. The calls to the validations are cascaded so that if there are multiple errors and the user corrects the first one to be reported, subsequent clicks of the Submit button find an error lower in the form than a previous one:

function validateForm(form) {
    if (isNotEmpty(form.name1)) {
        if (isNotEmpty(form.name2)) {
            if (isNotEmpty(form.eMail)) {
                if (isEMailAddr(form.eMail)) {
                    if (isChosen(form.continent)) {
                        if (isValidRadio(form.accept)) {
                            return true;
                        }
                    }
                }
            }
        }
    }
    return false;
}

Validation functions for a select element and radio button group are not among routines in Recipe 8.2, but are shown here:

// validate that the user made a selection other than default
function isChosen(select) {
    if (select.selectedIndex =  = 0) {
        alert("Please make a choice from the list.");
        return false;
    } else {
        return true;
    }
}
   
// validate that the user has checked one of the radio buttons
function isValidRadio(radio) {
    var valid = false;
    for (var i = 0; i < radio.length; i++) {
        if (radio[i].checked) {
            return true;
        }
    }
    alert("Make a choice from the radio buttons.");
    return false;
}

Note that the select element design assumes that the first item is an invalid choice.

All of the functions feed back to the main dispatching function. If any one validation fails, the dispatching function returns false to the onsubmit event handler, forcing it to evaluate to return false and thus aborting the submission. But if all validations return true, the dispatching function also returns true to the event handler, allowing the submission to continue normally.

Relying on the onsubmit event handler means that the user could disable JavaScript in the client to bypass client-side validation. This is a good reason to duplicate validation on the server. But if you'd rather perform all validation on the client and you know that all users have scriptable browsers, consider using a button-type input element instead of a true submit-type input element. Let the button's onclick event handler invoke the batch validation function and (if validation succeeds) the submit( ) method of the form object. Under these conditions, the user can't submit the form with JavaScript turned off.

8.3.4 See Also

Recipe 8.2 for individual data validation functions; Recipe 8.4 for focusing and selecting text in an invalid text field; Recipe 2.12 for date field validation suggestions.

    [ Team LiB ] Previous Section Next Section