Previous Page
Next Page

Making Fields Required

When filling out a form, you may want to specify particular fields that are required to be filled out by the user before the form can be submitted. You can use JavaScript to check that some or all fields are filled out. In this example, we use HTML, CSS, and JavaScript (Scripts 7.5, 7.6, and 7.7, respectively) to highlight fields that are not filled out with a red border and a yellow interior. The check occurs when the user clicks the form's Submit button.

Script 7.5. The HTML for the password check example.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
     <title>Password Check</title>
     <script language="Javascript" type="text/javascript" src="script03.js">
     </script>
     <link rel="stylesheet" href="script03.css" />
</head>
<body>
<form action="#">
     <p><label for="userName">Your name: <input type="text" size="30" id="userName" 
class="reqd" /></label></p>
     <p><label for="passwd1">Choose a password: <input type="password" id="passwd1" 
class="reqd" /></label></p>
     <p><label for="passwd2">Verify password: <input type="password" id="passwd2" 
class="reqd passwd1" /></label></p>
     <p><input type="submit" value="Submit" />&nbsp;<input type="reset" /></p>
</form>
</body>
</html>

Script 7.6. The CSS sets the style for invalid form elements.

body {
    color: #000;
    background-color: #FFF;
}
input.invalid {
    background-color: #FF9;
    border: 2px red inset;
}

label.invalid {
    color: #F00;
}

Script 7.7. This script serves as the basis for all the rest of the examples in this chapter; it's a framework that you can use to add additional validation checks.

window.onload = initForms;
function initForms() {
     for (var i=0; i< document.forms.length; i++) {
        document.forms[i].onsubmit = function() {return validForm();}
     }
}

function validForm() {
     var allGood = true;
     var allTags = document.getElementsByTagName ("*");

     for (var i=0; i<allTags.length; i++) {
        if (!validTag(allTags[i])) {
           allGood = false;
        }
     }
     return allGood;

     function validTag(thisTag) {
        var outClass = "";
        var allClasses = thisTag.className. split(" ");

        for (var j=0; j<allClasses.length; j++) {
           outClass += validBasedOnClass(allClasses[j]) + " ";
        }

        thisTag.className = outClass;

        if (outClass.indexOf("invalid") > -1) {
           thisTag.focus();
           if (thisTag.nodeName == "INPUT") {
              thisTag.select();
           }
           return false;
        }
        return true;

        function validBasedOnClass(thisClass) {
           var classBack = "";

           switch(thisClass) {
              case "":
              case "invalid":
                 break;
              case "reqd":
                 if (allGood && thisTag.value == "") classBack = "invalid ";
                 classBack += thisClass;
                 break;
              default:
                 classBack += thisClass;
           }
           return classBack;
        }
    }
}

Here's the big picture: the class attributes in the HTML store which checks we want the JavaScript to do. If a check is failed, we add invalid to the list of class attributes. Doing that causes (1) the form submission to fail, and (2) the CSS in Script 7.6 to change the appearance of the field on the page (Figure 7.5).

Figure 7.5. Make sure that passwords are entered by letting the user know there's a problem with a particular field.


To make fields required:

1.
function initForms() {
  for (var i=0; i< document.forms. length; i++) {
     document.forms[i].onsubmit = function() {return validForm();}



When the page first loads, the initForms() function is called. This function loops through every form on the page. For each one, it adds an event handler to that form's onsubmit: a call to function() {return validForm();}. This is another anonymous function, but this time it does something: it returns true or false to tell the browser whether or not to continue with the action attribute. When an onsubmit handler returns a value of false, the form doesn't get passed back to the server. The server only gets the form (running whatever CGI is stored in the action attribute) when we return a value of true.

2.
var allTags = document.getElementsByTagName("*");
document.getElementsByTagName("*")



is very usefulthat asterisk tells JavaScript to return an array containing every tag on the page. Then, we can just loop through the allTags variable looking for things of interest.

3.
for (var i=0; i<allTags.length; i++) {
   if (!validTag(allTags[i])) {
      allGood = false;



This loop searches through allTags, and the if conditional calls the validTag() function, which checks each tag to see if there's anything there that should keep the form from submitting this page. It's passed allTags[i], which is the object that we're currently processing. If any tag causes validTag() to return false, we set allGood to false. However, even if one is false, we still keep going through all the tags.

4.
return allGood;



We return allGood, to signify whether or not we're good to go.

5.
function validTag(thisTag) {



Create the validTag() function, and set it to receive the value thisTag.

6.
var allClasses = thisTag.className. split(" ");



For each tag, we want to look at every class attribute (remember, class can be set to have multiple attributes "like so and so and so"). The allClasses array is created and set based on thisTag.className.split(" "); which splits a string up into an array, broken up by the string that's passed in. Here, the string is a space, which would, for example, cause the string "this that and the other" to turn into an array of five elements: this, that, and, the, other.

We want to look at each class attribute, because class is where we're storing what we want each form field to have to provide. In this task, the one we care about is reqdrequired. If any form field has a class of reqd, it's got to contain something.

7.
for (var j=0; j<allClasses.length; j++) {
  outClass += validBasedOnClass(allClasses[j]) + " ";
}



This loop uses j as its loop variable because we're inside a loop that's using i. We loop around once for each class attribute in allClasses.

For each class, we perform: outClass += validBasedOnClass(allClasses[j]) + " "; This calls the validBasedOnClass() function (explained below), passing in the current class we're looking at. That function returns something, and that something, plus a space, is appended onto the outClass variable.

8.
thisTag.className = outClass;



When we've finished with the allClasses loop, we take the contents of outClass and put it into thisTag.className, overwriting the current class attribute for this form field. That's because it can change during this process, as we'll see very shortly.

9.
if (outClass.indexOf("invalid") > -1) {



Something that can be returned in the new class attribute is the word "invalid", so we check for it. If that's found anywhere in the new class, do the following, as there's a problem.

10.
thisTag.focus();



If this form field can take focus (remember, we discussed focus in Chapter 6), we want to put the focus into the field, and that's what this line does. This is a way of forcing the user to know which field is the problem.

11.
if (thisTag.nodeName == "INPUT") {
   thisTag.select();
}



Basically, these lines say, "This tag I'm looking at: is it an <input> tag? If so, select its value so that the user has an easier time modifying it."

12.
return false;



We're still inside the "invalid was returned" block, so we return false back to where we were called.

13.
return true;



If all is good and valid, we return true.

14.
function validBasedOnClass (thisClass) {



Begin the new validBasedOnClass() function, and set it to receive the value thisClass.

15.
var classBack = "";



Create the classBack variable, and fill it with nothing for now. This is going to contain the class to be returned, that is, the value we want to send back.

16.
switch(thisClass) {



The switch statement looks at the single class attribute that was passed in (in thisClass) and does something based on it.

17.
case "":
case "invalid":
  break;



If thisClass is empty or invalid, then break out of the conditional; otherwise, continue.

18.
case "reqd":
  if (allGood && thisTag.value == "") classBack = "invalid ";
  classBack += thisClass;
  break;



If the attribute being processed is reqd and allGood is true and the current value of the current tag is "" (i.e., nothing), then we set classBack to be invalid, because there's a problem, and we want to notify the user. After that, whether there was a problem or not, we append the current class to classBack so that it doesn't get lost.

19.
default:
  classBack += thisClass;



The default block is executed whenever something happens that isn't caught by one of the above cases. When that happens, it's a class we don't care about, so we just stick it onto classBack and don't fret.

20.
return classBack;



Finally, we return classBack.


Previous Page
Next Page