Previous: Introducing the Document Object Model Next: Summary

JavaScript and HTML Forms

In the previous section, you saw a number of the DOM objects you can access and alter using JavaScript. In this section, we're going to focus on one subset of the document object, the form object, and the various ways it can be manipulated.

The form Object

First, we should get the issue of multiple forms out of the way. In most cases, your forms will have names, thanks to the name attribute you use in the <form> element. If you give your form a name, as in name="myForm", you can easily access the elements of that form:

var name = document.myForm.custName.value 

Likewise, you've seen the steps you need to take to either pass a value to a function, pass a pointer to a function, or pass nothing to a function and let the function directly access the form via the document object. Easy enough.

But, as was mentioned, the document object has a property called forms that's actually an array of the forms stored in that document. Assuming myForm in the preceding example is the first form in the document, it could also be accessed in this way:

var name = document.forms[0].custName.value

That's perfectly valid. And at times, you may find it useful to access forms using the array, particularly if you need to access them automatically:

for (x=0; x<3; x=x+1) {
 var formName[x] = document.forms[x].name
}

With that sort of for loop, you could set each form's name to an array, making them individually accessible using the formName array.

Each form object (whether it's accessed as an array or by name) has a number of properties, just like the document and window objects do. The form object's properties include the following:

action The action URL, as set in the <form action=" "> attribute
method The method attribute's value (get or post)
name The name of the form, as set in the <form name=" "> attribute
length The number of elements (input, textarea, and select elements) in the form
target The window or frame that is targeted by the form
elements An array that holds all the elements (input, textarea, and select elements) in that form

The form object also includes some methods, including reset() and submit(), which can be used as if the Reset or Submit buttons were clicked by the user.

Form Error Checking with JavaScript

JavaScript and event handling are ideal for checking your user's form entries. As users type, JavaScript can be working in the background to make sure that the users' entries are correctly coded, have the right number of characters, and so on. You'll find that you can check pretty much any form element, although you'll most likely want to focus on entry boxes and textarea elements.

Let's start with an example script. Listing 3 shows you an entire page that has been designed to enable form entry, while checking the user's input in the ZIP Code entry box to make sure the ZIP Code is a valid number.

Listing 3 Verifying Form Data with JavaScript

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Checking the Zip</title>
<meta http-equiv="Content-Script-Type" content="text/javascript">

<script>
<!--

function zipCheck() 
{
 var zipStr = custForm.zipCode.value;
 
 if (zipStr == "") {
   alert("Please enter a five digit number for your Zip code");
   return(-1);
   }
 if (zipStr.length != 5) {
   alert ("Your Zip code entry should be 5 digits");
   return(-1);
   }
 return(0);
}
 
function checkSend()
 {
 var passCheck = zipCheck();
 if (passCheck == -1) {
   return;
 }
 else {
   custForm.submit();
 }
}
 
// end hiding -->
</script>

</head>

<body>

<h1>Please fill out the following form:</h1>

<form action="cgi-bin/address.pl" method="post" name="custForm">

<pre>

Name:  <input type="text" size="20" name="name">
Address: <input type="text" size="50" name="address">
City:  <input type="text" size="30" name="city">
State:  <input type="text" size="2" name="state">
Zip:   <input type="text" size="5" NAME="zipCode"
     onBlur = "zipCheck()">
Email:  <input type="text" size="40" Name="email">

<input type="button" value="Send It" onClick = "checkSend()">
</form>
</body>
</html>

This form works by using the onblur event handler to notice when the user moves away from the ZIP entry box—either by clicking in another box or by pressing the Tab key. The event handler then invokes the zipCheck function, which makes sure that the ZIP Code has been entered correctly. First, if nothing has been entered, an alert pops up, letting the user know that the ZIP Code is required. This is done by checking if the zipStr variable is empty:

if (zipStr == "") {

Next, the function checks that the ZIP Code entered is five characters long—not longer or shorter. It does so with this if statement:

if (zipStr.length != 5) {

If the ZIP Code is the correct length, nothing happens and the user can continue entering items on the form. If the ZIP Code isn't the correct length, an alert pops up.

Of course, the user could either ignore the alert or change the ZIP Code but still get it wrong. In that case, the zipCheck function gets called a second time, from within the checkSend function:

var passCheck = zipCheck();

If the ZIP Code is still incorrect, the zipCheck function will return the value –1, which the checkSend function is on the lookout for:

 if (passCheck == -1) {
   return;
 }

So, if the ZIP Code is still not correctly entered, the checkSend function will return to the form so the user can try again.

If the user did enter a correctly sized ZIP Code this time, the form is submitted:

 else {
   custForm.submit();
 }

See Figure 3 for an example of what happens when the user enters a ZIP Code incorrectly.

Figure 3 If the ZIP Code isn't entered correctly, an alert box appears.

Actually, we haven't completely checked for a valid ZIP Code. Indeed, this could get as complicated as you want it to be. For instance, you could add code that makes sure the ZIP Code is made up of numbers, thus disallowing characters. One way to do that is using the charAt() method of the String object, which can check each character to make sure it falls within the correct range of 0 through 9. Here's the expanded zipCheck function:

function zipCheck() 
{
 var zipStr = custForm.zipCode.value;
 
 if (zipStr == "") 
   {
   alert("Please enter a five digit number for your Zip code");
   return(-1);
   }
 if (zipStr.length != 5) 
   {
   alert ("Your Zip code entry should be 5 digits");
   return(-1);
   }
 
 for (x=0; x < 5; x++)
 { 
   if ((zipStr.charAt(x) < "0") || (zipStr.charAt(x) > "9"))
   { 
     alert("All characters in the Zip code should be numbers."); 
     return(-1);
   } 
  } 
 return(0);

}

Now, with this one, we've added another check, just in case the user squirms by the first two. This third check begins with a for loop, so that the script can move through the length of the ZIP Code and check each character:

for (x=0; x < 5; x++)
 {

Using the for loop, we can move through each index value (from 0 to 4) of the zipStr array. Then, using a clever little if statement, the function checks each character to see if it's a number (that is, it makes sure the character isn't below 0 or above 9):

if ((zipStr.charAt(x) < "0") || (zipStr.charAt(x) > "9"))
   { 

The || means "or," by the way. This expression evaluates as "if the character is less than zero or if the character is more than 9." If one of those is true, the alert is triggered:

alert("All characters in the Zip code should be numbers."); 
     return(-1);

If the alert isn't triggered, the if statement is over and the user is none the wiser for having been checked.

Client-side JavaScript

Another advantage of JavaScript is that it gives you an option for dealing with forms without ever worrying about a CGI script. In some cases, you'll find that you don't have access to the CGI directory on your server. In other cases, you simply don't want to go to the hassle of creating a CGI script. Listing 4 shows an example of such a script.

Listing 4 The Completely Client-Side Form

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Customer Survey Form</title>
<script>
<!--
function processform () {
   var newline = "\n";
   
   var result_str = "";
   var Form1 = document.form1;
   result_str += Form1.first_name.value + " " + Form1.last_name.value + newline;
   result_str += Form1.email.value + newline;
   
   for (x = 0; x < Form1.where.length; x++) {
     if (Form1.where[x].checked) {
     result_str += Form1.where[x].value + newline;
     break;
     }
   }

   if (Form1.desktop.checked) result_str += "desktop computers" + newline;
   if (Form1.notebook.checked) result_str += "notebook computers" + newline;
   if (Form1.peripherals.checked) result_str += "peripherals" + newline; 
   if (Form1.software.checked) result_str += "software" + newline;
   
   document.form2.results.value = result_str;
   
   return;
   }
   
// -->
</script>
</head>

<body>

<h1>Web Site Survey</h1>

<form name="form1" id="form1">

<table cellpadding="5">
<tr>
<td>First name:</td> <td><input type="text" name="first_name" size="40" maxlength="40" /></td>
</tr>
<tr>
<td>Last name:</td> <td><input type="text" name="last_name" size="40" maxlength="40" /></td>
</tr>
<tr>
<td>E-mail address:</td> <td><input type="text" name="email" size="40" maxlength="40" /></td>
</tr>
</table>

<p>
<b>Where you heard about us:</b></p>
<input type="radio" name="where" value="Web" checked="checked">Web Search or Link</input><br />
<input type="radio" name="where" value="Advertisement">Radio or TV Ad</input><br />
<input type="radio" name="where" value="Press Mention">Article or press mention</input><br />
<input type="radio" name="where" value="Other">Other</input><br />
</p>

<p>
<b>What products would you like more information about? (check all that apply)</b><br />
<input type="checkbox" name="desktop"> desktop computers
<input type="checkbox" name="notebook"> notebook computers
<input type="checkbox" name="peripherals"> peripherals
<input type="checkbox" name="software"> software
</p>

<button name="submit" type="button" onclick="processform ()">
<span style="font-family: Arial, Helvetica; font-variant: small-caps; font-size: 12pt"> Submit Survey</span>
</button>
<button name="reset" type="reset">
<span style="font-family: Arial, Helvetica; font-variant: small-caps; font-size: 12pt"> Clear Page</span>
</button>


</form>

<hr />

<form name="form2" id="form2" action="mailto:survey@fakecorp.net">

<p>Check the entries below for accuracy. If they're accurate, then enter a comment on the last line (if desired) and click Send It to send the form via e-mail.</p>
<textarea name="results" cols="40" rows="10">
</textarea>
<button name="submit" type="submit">
<span style="font-family: Arial, Helvetica; font-variant: small-caps; font-size: 12pt"> Send It!</span>
</button>

</form>

</body>
</html>

This script isn't too terribly complicated, but it's worth examining. First, the script accepts values from the user via the survey form. Then, it translates those values, via the script up top, into text values, which are fed into the second form's text area. Then, the user is able to edit the data (add a comment, for instance, as shown in Figure 4) and click the Send It! button to send the form as an e-mail message.

Figure 4 Here the user can edit the data before sending it.

NOTE

The data will still arrive in the post format (see Chapter 15, "Adding HTML Forms," in Absolute Beginner's Guide to Creating Web Pages, Second Edition), but there's only one field to worry about working with once the text has been parsed.

This example shows that it's important to get the correct values from checkboxes and radio buttons. Listing 4 shows two different ways to do that. To begin, let's look at radio buttons. You need to determine which of the radio buttons has been checked, and then you can work with that value. With radio buttons, the values are stored in a special array, so we use a loop to access them:

for (x = 0; x < Form1.where.length; x++) {
     if (Form1.where[x].checked) {
     result_str += Form1.where[x].value + newline;
     break;
     }
   }

All the radio buttons are stored in an array of objects that are named for the name attribute used to create the radio buttons—in this case, that's where. Within each where object, the property checked can be used to determine if that value has been selected. When you find the checked where object, the associated value property is what you're interested in. So, the preceding loop looks at each checked property. When it finds one that's true, that value is used (in this case, it's added to result_str) and the for loop stops, thanks to the break command.

The second example shows how to deal with a series of checkboxes. Again, you test the checked property. Because each checkbox has its own name attribute, however, you don't need an array or a loop. Each checkbox is evaluated individually to see if it's checked. If it is, its value is used:

   if (Form1.desktop.checked) result_str += "desktop computers" + newline;
   if (Form1.notebook.checked) result_str += "notebook computers" + newline;
   if (Form1.peripherals.checked) result_str += "peripherals" + newline; 
   if (Form1.software.checked) result_str += "software" + newline;

If the box is checked, a string is added to the result_str; if it isn't checked, the script moves to the next if statement.

(c)JavaScript for Redirection and Frames

You've seen how to access and alter some of the main objects of the DOM, and you've seen how to verify form data and use JavaScript to alter form data and for client-side processing. In this section, let's take a quick look at some other little JavaScript tricks, including redirecting a browser, building links in JavaScript, and using JavaScript with frames.

Browser Redirection

It can be useful to figure out which browser your user is using and redirect that user to a particular page. Not only is it sometimes important to know if the browser is Internet Explorer, Netscape, or another brand, but you can also use browser redirection to determine whether or not a browser supports JavaScript and make sure your user automatically visits the appropriate page.

For browser redirection, you'll use another object we haven't touched on much, the navigator object. Using this object and its properties, you can get a sense of which browser version you're dealing with. The navigator.appName property stores a string that tells you the full name of the application, the navigator.userAgent object tells you the general level that the browser is compatible with (as in Mozilla/4.0, which could be any Netscape-compatible 4.0-level browser), and the navigator.appVersion property reports the version number.

So, the first thing you can do with this knowledge is create a document that will show you all the properties of the browser that access that document:

<script type="text/javascript">
document.writeln ("navigator.appName: " + navigator.appName + "<br \/>");
document.writeln ("navigator.userAgent: " + navigator.userAgent + "<br \/>");
document.writeln ("navigator.appVersion: " + navigator.appVersion + "<br \/>");
</script>

Although this information is useful, it can be a bit more difficult to turn it into a perfectly useful browser redirection script—one that notes the version and loads a particular URL in response. That's because you need to actually have the script parse those names and figure them out so you know which browser is which. This can be done with a series of if statements, as shown in Listing 5.

Listing 5 Browser Redirection

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Browser Detector</title>
<script type="text/javascript">
<!--
var browserAppName = navigator.appName; 
if (browserAppName == "Netscape") { 
  window.location = "net_index.html";
  }
else { 
 if (browserAppName == "Microsoft Internet Explorer"){
  window.location = "ie_index.html";
  }
 else {
  window.location = "index.html";
  }
}
//-->
</script>
</head>

<body>
<h1>Browser Detector</h1>
<p>If this page doesn't refresh, then you may have a browser that isn't JavaScript compatible, or you may have JavaScript turned off. Please click to visit our <a href="index.html">non-JavaScript index</a> page.</p>
</body>
</html>

Of course, you already may have figured out that if your goal is simply to detect JavaScript versus non-JavaScript, the best way is to include a JavaScript redirect command—just a simple window.location = "newpage.html" command will suffice. If that page doesn't redirect, you can assume the user doesn't have a JavaScript-capable browser, so you can offer him a link to the non-scripted part of your site.

NOTE

Sometimes you'll need to know more than simply the brand of browser. In that case, you may also want to test the .appVersion property to see what version of the application you've encountered. Also, "Adding Dynamic HTML Elements" has a more sophisticated look at browser detection (often called browser sniffing) in the section "Cross-Browser DHTML Example."

The JavaScript Link Menu

One of the form elements we haven't yet discussed is the <select> element, partly because it's the odd duck of form elements and JavaScript. In this example, though, we'll create a navigation menu that you can use on your pages to allow your users to quickly move to a different page. And we'll use a <select> menu to create that navigation menu. Listing 6 shows this in action.

Listing 6 The <select> Menu and JavaScript

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Change Page</title>
<script type="text/javaScript">
<!--
 function changePage(theSelect) {
   var x = theSelect.selectedIndex;
   window.location.href = theSelect.options[x].text;
   }
// -->
</script>

</head>
<body>
<div align="center">

<form name="changeForm">

<p>
<select name="changeSelect" onchange="changePage(this)">
<option selected="select">Choose a Page</option>
<option>index.html</option>
<option>products.html</option>
<option>service.html</option>
<option>about.html</option>
<option>help.html</option>
</select> 
</p>

</form>
</div>

<hr />

<h1>Welcome to the Site!</h1>

<p>Markup...</p>

</body>
</html>

With a <select> menu, there are no assigned values, as with most other form elements. Instead, the text of the menu itself is what is stored, in a text property of the select menu's object. Also, the selected value is stored in a selectedIndex property. So, using the following function, the script simply consults the selectedIndex property, and then uses that index to access the text of the selected option (which is stored in the options array):

function changePage(theSelect) {
   var x = theSelect.selectedIndex;
   window.location.href = theSelect.options[x].text;
   }

Programmatically, that's how you get items out of a <select> element. Figure 5 shows this page in action.

Figure 5 Changing pages with a <select> menu and JavaScript.

Of course, the way this script and menu are set up, you'll need to copy them to each of the pages involved if you want the menu as a fixture on your Web site. There is another option—you could use frames, as discussed next.

JavaScript and HTML Frames

So, assuming you are working with a browser that's capable of JavaScript, wouldn't it be interesting to use it for the entire interface? One way to do that is to use HTML frames to create the interface, while offering your users a pull-down menu for navigation. In this section we'll create such a site, which will be designed as an archive of Web articles, easily accessed via a menu.

As with any frames interface, you're going to need a number of different documents to make this interface work. First, a <frameset> document will be used to bring the whole thing together. Second, you'll need a navigation page that includes a <select> menu, as discussed in the previous section. With just a few tweaks, that menu can be used for this frames-based approach as well.

In addition to those two elements, you'll need a document that loads when the frameset appears. In this case, it will be the default page that explains the interface. And of course, you'll need all the content pages that are to appear in the frames interface.

To begin, Listing 7 shows the frameset document.

Listing 7 The Frameset Document

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>The Article Viewer</title>
</head>

<frameset rows="150, *">
  <frame src="navigate.html" />
  <frame src="default.html" name="main_viewer" />
</frameset>

Next up, we need navigate.html, which will be the top frame of the frameset and is based on the <select> menu example used in the previous section. Listing 8 shows that example, now tweaked to target the main_viewer frame of the frameset, using the object reference top.main_viewer.location.href. As you may remember from Chapter 12, "Creating Sites with HTML Frames," in Absolute Beginner's Guide to Creating Web Pages, Second Edition, top is a special target that means, ultimately, the browser window. It's also an object in the DOM, which includes all the frames of the frameset, so that those frames can be assigned URLs programmatically.

Note, also, that this version of the navigate page has been altered so that the user, instead of seeing URLs, sees a description, which is translated into the appropriate URL. That's done simply by creating an array of URLs, which are referenced using the index number of the selection in the menu. You'll need to carefully construct this array (to make sure that the <option> entries in the <select> element correspond to this list of URLs in the array), but it's a tricky way to make the menu a little more readable.

Listing 8 The navigate.html Page

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Navigate Page</title>
<script type="text/javaScript">
<!--
 function changePage(theSelect) {
   pageArray = new Array("default.html", "article1.html", "article2.html", "article3.html", "article4.html", "article5.html");
   var x = theSelect.selectedIndex;
   top.main_viewer.location.href = pageArray[x];
   }
// -->
</script>

</head>
<body style="background-color: yellow">
<div align="center">

<h1>FakeCorp Article Archive</h1>

<form name="changeForm">

<p>What article would you like to read?</p>

<p>
<select name="changeSelect" onchange="changePage(this)">
<option selected="select">Default Page</option>
<option>The Skinny on RAM</option>
<option>Hard Drive Technologies</option>
<option>Choosing a Monitor</option>
<option>Upgrading and Swapping Processors</option>
<option>Troubleshooting the OS</option>
</select> 
</p>

</form>
</div>

</body>
</html>

Now, we need a default.html page that can appear when the frameset is first loaded. This page is a simple XHTML document that tells the user a little about the interface, offers any news or updates, and enables incompatible browsers to avoid the frames interface. Listing 9 shows the page.

Listing 9 The default.html Page

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Default Page</title>
</head>

<body style="margin: 24pt">
<h1>Welcome to the Article Viewer!</h1>

<p>Using the menu above, select the article that you'd like to view. It should load automatically in this window. If you'd like to return to this page, choose Default Page from the menu. </p>

<p>If you'd prefer to view this site without a frames interface, or if your browser doesn't support JavaScript, please visit or <a href="noframes.html">no-frames interface</a> to read these articles.</p>

<h2>Latest Additions</h2>

<p><strong>10/13 --</strong> We've just posted an article that looks into the various RAM technologies to help you decide which is right for your model of computer. Check it out for in-depth coverage of the numbers and statistics you need to know to buy reliable RAM.</p>

<p><strong>10/5 --</strong> Check out Upgrading and Swapping Processors for step-by-step discussion on deciding whether it's time to upgrade your PC's processor and, if so, how you should go about it.</p>

</body>
</html>

Now, assuming the other articles are in place (those referenced in the array that was created for the navigate.html page), we're ready to put this frameset to use. Figure 6 shows the final frameset in action.

Figure 6 Using a frameset and a special <select> menu navigation page, you can create a JavaScript-based interface.

Previous: Introducing the Document Object Model Next: Summary