Form Validation

(Reading: We strongly suggest you read pages 395-398 of JavaScript: A Beginner's Guide with these notes.)

Motivation

One particularly useful application of fruitful (value-returning) functions is for validating user input. On forms, it's a good idea to verify that the information provided by the user is correct before processing it. For example, we might check that:

Here are two examples of form validation from previous CS110 projects:

Here is the sample form that we will be working with in today's lecture. (View source to see the HTML code.)

A Simple Example: Name Validation

As a first example, let's validate that the name field in our form is not blank. First, we need to know how to reference the text field where the user types in her name. Here is the part of the form that defines the name field:

... Please enter your name: ... other inputs here

So, the JavaScript variable that holds the contents of the name field is:

document.easyform.yourname.value

To validate the name field, we want to do something like this (the green text is just English description, as opposed to JavaScript):

if (the name text box is blank ) {
     Show an alert with a reminder message 
     name is not valid
} else { 
     name is valid
}

English JavaScript

the name text box is blank

document.easyform.yourname.value == ""

Show an alert with a reminder message

alert("Please provide your name.");

Form is done

return true;

Form is not done yet

return false;

Translation:

The most important observation is this: We want validName() to be a fruitful function that returns a boolean:

In the remainder of these notes, we will use the term boolean function to refer to a fruitful function that returns a boolean value.

Also, the validName() function returns true/false as to whether the name field is valid. You can easily imagine similar functions that validate other text inputs, such as validAddress(), validState, validZip and so forth. We'll refer to functions that validate one field as field validators.

Using a Field Validator in Form Validation

Now that we know how to define field validators, how can we use that to validate a form? The default behavior of the SUBMIT button is to send the form's fields to the server when clicked. Its code is simply

The onClick attribute is optional if we want the default behavior (that is, we want the form's action performed). But this is not what we want here. We want

      onClick = "return true;"

if the yourname field is filled, and

      onClick = "return false;"

if the yourname field is empty.

It turns out that if the onClick handler for a submit button returns false, then its default behavior (the submission of the form) will not be performed.

(What if no return value is specified for the onClick handler for a submit button? Empirically, many browsers will still perform the default action (submission of the form) in this case. So explicitly returning false seems to be the only way to cancel the default action.)

So what we really want is something like

      onClick="if (validName() == true) {
                     return true;   /* submit the form */
               } else {
                     return false;  /* don't submit the form */
               }"

Notice that, because validName() returns true or false exactly when we want, the preceding code can be simplified to:

      onClick = "return validName();"

Therefore, the full code for the SUBMIT button is:

Here is what happens: When the user clicks the button, the onClick script is executed. This says "return validName();". Therefore the function validName() is executed. When it finishes execution, it will return a boolean value, either true or false. If validName() returns true, then the onClick code will be equivalent to

onClick = "return true;"

This will effectively let the submission of the form proceed. If, on the other hand, validName() returns false, then the onClick code will be equivalent to

onClick = "return false;"

and the submission of the form will be halted.

Exercise 1:

Here is the validated form, so you can see it in action.

Here is a page that contains two forms (two copies of the form). Does name validation work on the second form. Why or why not?

Year Validation

Now let's validate the year field of our form. This is more complex than just ensuring the field is non-empty. We want to make sure that it's a valid year. In this context we'll define a valid year as one that is in the range from 1900 to the current year.

The part of the form that defines the year field is

<form name = "easyform" ...  >
  ...
  <p>Please enter your birth year:
  <input type = "text" size = "5" name = "birthyear">
  ... 
</form>

so the JavaScript variable that holds the contents of the year field is:

document.easyform.birthyear.value

We can test for a valid year via the following boolean function:

function validBirthYear() {
  var year = parseInt(document.easyform.birthyear.value); 
  var currentYear = (new Date()).getFullYear();
  if ((year >= 1900) && (year <= currentYear)) {
    return true;
  } else {
    alert("Please provide a valid birth year\n" 
          + "(in the range 1900 -- current year)")
    return false;
  }
}

If we want our form to validate just the year field, we can simply change the onClick handler of the SUBMIT button to use validBirthYear()>:

<input type = "submit" 
       value = "Click Here to Submit"              
       onClick = "return validBirthYear();"
>

Here's a version of our form with year validation (but not name validation).

Combining Name and Year Validation

Of course, we don't want a form that validates just one field. We want it to validate multiple fields! For example, we'd like our form to validate both the name and year fields. How can we do that?

Validating multiple fields is easy if we've defined separate boolean functions for validating the individual field. To validate multiple fields in a form, we can define a boolean function validForm() that returns true exactly when all all the fields are validated and returns false otherwise (i.e., when at least one field doesn't validate). The validForm() function simply uses && to combine invocations of the individual field validation functions.

For example, to validate both the name and year field in our sample form, we define

function validForm() {
    var nameOK = validName();
    var birthyearOK = validBirthYear();
    return nameOK && birthyearOK;
}

and change the onClick handler of the SUBMIT button to use this new function:

<input type = "submit" 
       value = "Click Here to Submit"              
       onClick = "return validForm();"
>

Here's a version of our form that validates both name and year.

The approach described above is a modular in the sense that we've broken out the validation of individual fields into these field validatior functions. The modular approach to validating forms by combining individual field validators has many benefits, the most important of which are:

Note the naming scheme we've adopted: a field fred is validated by a validFred() function and the result is stored in a fredOK boolean variable, ready to be combined with the other boolean variables in one final &&

Warning: Most validators you'll see in textbooks and in the wild are not constructed in this modular fashion. Instead, form validation is often performed by a single large JavaScript function whose body is a rat's nest of conditionals. But now that you know the modular approach, you should avoid the bad style you see elsewhere!

Validating Select Menus

Pull-down menus, like the where do you live menu in our example, pose a very different validation task. The issue is not checking whether the user typed any text, but whether they made a choice.

The first thing, of course, is to make sure that you can tell whether they made a choice. For example, it's common to have a menu like the following:

The trouble with this menu is that if the menu shows Science Center, you don't know whether the user meant to make that choice, or forgot to make any choice and the initial value is still there. So, you need to make sure that the initial choice is invalid. For example:

It doesn't matter what the text of that initial option is, it just needs to be there. (If you want to make the pre-selected option in the middle of the menu, you can do that, too.)

Now, how can you tell what choice the user made? Each select menu comes with a property called selectedIndex which tells you the numerical index (starting at zero because that's how computer scientists count).

Here's one way of validating that field:

Radio Buttons

The key with validating text inputs and select menus was to look them up by name. How are the radio buttons named? Consider the following HTML code from our form:

Here is the part of our form that uses radio buttons:

You will graduate from Wellesley Class of:
2010 2011 2012 2013

They all have the same name, because logically they belong to the same group! How do we distinguish which is which? By referring to them by number. Oh, we have to remember that computer Scientists start counting at — ahem — zero. So:

With text inputs, we were interested in the value attribute, since that's what the user typed. However, with radio buttons, the values are all part of the form, and we're only interested in which one was chosen. How can we do that? It turns out that each radio button input has a checked property which is true if and only iff that button is currently checked (chosen). For example, if the user is the class of 2010 and has chosen that option, the following expression will be true:

document.easyform.graduation[0].checked

Since users can only check one radio button, radio buttons are validated to make sure that something was chosen (checked). Thus, the logic is that at least one has to be checked. Equivalently, complain if none of them has been checked. In other words, if the first one isn't checked, and the second one isn't checked, and. Here is some code that does the trick:

    function validGraduation() {
        if( the first radio button is checked OR
            the second radio button is checked OR
            the third radio button is checked OR
            the fourth radio button is checked ) {
             field is valid
        } else {
             field is NOT valid
        }
    }       

Now we're ready to translate that logic into JavaScript:

That can, of course, be simplified to the following:

Validating Checkboxes

Checkboxes are just like radio buttons, except that you can check more than one, so validation often takes more complicated guises, such as choose three options or choose no more than four and so forth, as we saw in our example form:

What were your favorite things about Wellesley? (Choose 1 to 3):

  1. close friends
  2. awesome professors
  3. exciting classes
  4. great sports teams
  5. clubs, orgs, and other extra-curricular things
  6. proximity to Boston (Harvard, MIT ...)
  7. women's college

Checking that at least one option was chosen is just like radio button validation, so we'll skip that and go on to something harder, namely counting.

The idea is that if the checked property for an input is true, we'll add one to a counter. Start the counter at zero, and when the code is done, we'll know how many were checked. (We've seen code like this before.)

Notice that we separated the counting of the checkmarks from the question of whether the field is valid. We could have combined them, but separating them makes the code clearer, easier to understand, and easier to re-use. If someone needs to change the validation from 1-3 to 2-4 checkmarks, then only have to look at the two-line validFavs function, and they can ignore the eight-line countFavs function.

Putting it All Together

In the section about form validation above, we saw how to combine field validators for the name and birthyear fields to validate both of these fields in a form. We assigned variables to the boolean values returned by each validator and then used a big && expression to determine whether they were all true (valid). We can easily extend this idea to combine all the modular field validators in any form. In our sample form, for instance, we can validate all the fields as follows:

What's nice about making each its own function is that you can test them individually, and that's really helpful in narrowing down where the bug is when you have a complex form with many inputs to validate. This is an aspect of modularity, which is one of the big ideas in computer science.

Try it: validated whole form

Feedback to the User

If we wish to display a message when the form is successfully filled out, we can do that, too:

The more important feedback is to notify the user of what inputs they need to fix in order to submit the form. We could, of course, pop up an alert for each one, but that's not a good idea because alerts are annoying. Far better to mark each one by modifying the style or content of the document, using the JavaScript DOM.

Here, we've surrounded each question with a div with an id, so we can pick out exactly that div. Then, we're going to modify its innerHTML to add a message about it, and we're going to modify the border as well.

See it in action: validated whole form with marking

Summary

Here is a condensed version of the material from these notes.

Further Information and Examples

Note that beyond here is information that we think you might find interesting and useful, but which you will not be responsible for. It's for the intellectually curious student.

The onSubmit Event

In the section about form validation above, we used the onClick event handler to execute our form validation code. However, there is another place we can put form validation code, namely an onSubmit event handler. When a form is submitted, an event called submit is generated. This event is associated with the form itself, not any particular submit button.

To use it, remove the onClick event handler and write the same code as the onSubmit event handler for the form:

<form name = "easyform"
      method  = "post"
      action  = "http://cs.wellesley.edu/cgi-bin/eform.cgi" 
      onSubmit = "return validName();" >

NOTE: You only need to invoke validName() once, either

Not in both!

Why might you use an onSubmit event handler instead of an onClick event handler? One case is that in some forms, it's convenient to have several submit buttons. If we want to do the same form validation in every case, we either copy the same code to each onClick event handler or, better, put the code in the onSubmit event handler.

Short-Circuit Operators

The use of boolean variables in our examples above avoided an interesting issue, namely the fact that the && operator is a short-circuiting operator. (So is the || operator.) Short-circuiting means that the evaluation of the expression stops as soon as the answer is known. Consider the following:

Try running it:

You'll notice that the code stops as soon as you stop following the instructions. It never asks you another question after that. Why? Because the various equality tests are being combined with and (&&), and and is necessarily false if any of the operands is false. The short-circuiting is to stop looking at operands as soon as you find one that is false. (Similarly, the short-circuiting with or is to stop as soon as you find something that is true.)

Now, the and and or operators are always short-circuiting in JavaScript. We didn't notice earlier because we has already executed all our field validators, storing the return values in boolean variables. Having done so, the short-circuiting didn't prevent the invocation of any of our field validators.

Suppose, however, that we had written the validForm function as follows:

With this code, if the name isn't valid, the short-circuiting means that validYear is never invoked, so the user doesn't find out whether that part of the form is valid. The validForm function stops as soon as it finds an invalid field.

Non-Short-Circuit Evaluation

The short-circuit behavior of && is desirable when validation feedback is done with alert boxes, since it would be very annoying to have an alert box pop up for every invalid field.

But in other forms of validation (in which invalid fields are colored red, for instance), we want all invalid fields to be indicated, not just the first. That's the approach we advocate above, since alerts are so annoying.

Suppose we do want to have non-short-circuit evaluation but we also like the embedded style of programming, without lots of boolean variables?

A second approach is to build our own non-short-circuit and() function as follows:

// Non-short-circuit and() function 
function and (bool1, bool2) {
  return bool1 && bool2; 
}

Essentially, this ways still uses lots of boolean variables, but it hides them as the parameters of the and() function.

But the and() function only takes two arguments. What if we have three, four or even more expressions to combine with and()? Clearly, we could define a bunch of related functions, like this:

function and2(b1,b2) { return b1 && b2; } function and3(b1,b2,b3) { return b1 && b2 && b3 ; } function and4(b1,b2,b3,b4) { return b1 && b2 && b3 && b4 ; } ...

but that would be yucky. An alternative is to use grouping, just like we do with addition, multiplication and lots of other associative operators:

The number of closing parens on the line with the last prompt is terrifying when you first encounter it, but if you build up the expression, you can see why each exists.

Try running it:

Solutions to Exercises

Optional reading: Thau Chapter 11.