Полезная информация

Chapter 6

Creating Interactive Forms


CONTENTS


Working with forms is the cornerstone of many of the JavaScript programs currently available on the World Wide Web. From simple spreadsheets to conversion calculators and color-pickers, many scripts use forms and their associated properties, methods, and event handlers to produce sophisticated interactive programs.

In order to effectively use forms in JavaScript, you need to understand the form object and its properties and methods and to have a firm command of the events generated by different form elements.

In this chapter, you will learn this through the following topics:

The form Object

The form object is one of the most heavily used objects in JavaScript scripts written for Navigator. As a programmer, by using the form object, you have at your disposal information about the elements in a form and their values and can alter many of these values as needed.

A separate instance of the form object is created for each form in a document. As you learn later in the section about the forms[] array, forms all have a numeric index. They can also be referred to by name.

Properties of the form Object

Table 6.1 outlines the properties available with the form object.

Table 6.1. Properties of the form object.

PropertyDescription
action String containing the value of the ACTION attribute of the FORM tag
elements Array containing an entry for each element in the form (such as checkboxes, text fields, and selection lists)
encoding String containing the MIME type used for encoding the form contents sent to the server. Reflects the EncTYPE attribute of the
FORM tag.
name String containing the value of the NAME attribute of the FORM tag
target String containing the name of the window targeted by a form submission

As you learn later in the section on the elements[] array, each of the elements of the form is itself an object with associated properties and methods. Elements can be referred to by name, as well as through their numeric index in the elements[] array.

The action Property

With this property, you can ascertain the action specified in the form definition. For instance, in a form defined with the following

<FORM METHOD=POST ACTION="/cgi-bin/test.pl">

the action property has a value of "/cgi-bin/test.pl".

The elements Property

This property is covered in more depth later in the section about the elements[] array.

The encoding Property

The encoding property reflects the MIME type, which is used to encode the data submitted from a form to the server. In practical terms, this means that the property reflects the EncTYPE attribute of the FORM tag, and you can set the encoding of a form by changing the value of this property.

This is useful when you want to upload a file to be processed by a CGI script on the server. More details about form-based file upload is available in the Internet Engineering Task Force's Request for Comments document number 1867 at the following site:

http://www.ics.uci.edu/pub/ietf/html/rfc1867.txt

The name Property

This property provides the programmer with the name specified in the form definition. In a form defined with the tag

<FORM METHOD=POST ACTION="/cgi-bin/test.pl" NAME="thisform">

the name property has a value of "thisform".

Note
Using named forms is especially useful in documents with multiple forms where the JavaScript scripts must work with all the forms in the document.

The target Property

The target property is similar to the action and name properties and makes the content of the TARGET attribute available to the programmer. In the FORM definition

<FORM METHOD=POST ACTION="/cgi-bin/test.pl" NAME="thisform" TARGET="thatframe">

the target property has a value of "thatframe".

Note
The TARGET attribute is particularly useful in the context of frames, which we discuss in Chapter 8, "Frames, Documents, and Windows."

It is possible to dynamically change the target of a form by assigning a new value to the target property. In the preceding example, the target could be changed from thatframe to anotherframe by using

document.thisform.target = "anotherframe";

It is important to note that target can only be assigned a string literal. It cannot be assigned an expression or a variable.

Methods of the form Object

There is only one method available with the form object: submit(). As mentioned in Chapter 5, "Events in JavaScript," this method emulates a click on the submit button of a form without invoking the onSubmit event handler.

For instance, in the following script, the form has no submit button and can be submitted when the user enters the correct value in the text field. The onSubmit event handler, which returns false, ensures that the form is not submitted if the user hits Return in the text entry field.

<HTML>

<HEAD>
<TITLE>submit() Example</TITLE>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

function checkValue(form) {

  if (form.answer.value == "100")
    form.submit();
  else
    form.answer.value = "";

}

// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</HEAD>

<BODY>

<FORM METHOD=POST ACTION="/cgi-bin/correct.pl" onSubmit="return false;">
What is 10 * 10? <INPUT TYPE="text" NAME="answer"
onChange="checkValue(this.form);">
</FORM>

</BODY>

</HTML>

Event Handlers for the form Object

Just as it has only one method, the form object has only a single event handler associated with it: onSubmit. This event handler is invoked when the user submits a form. For instance, in the following script, when the user submits the form, she is thanked for doing so.

<HTML>

<HEAD>
<TITLE>onSubmit Example</TITLE>
</HEAD>

<BODY>
<FORM METHOD=POST ACTION="/cgi-bin/test.pl"
onSubmit="alert('Thanks for taking the test.');">
What is 10 * 10? <INPUT TYPE="text" NAME="answer">
<BR>

<INPUT TYPE="submit">
</FORM>
</BODY>

</HTML>

Working with Form Elements

Forms are made up of a variety of elements that enable users to provide information. Traditionally, the content (or value) of these elements is passed to programs on the server through an interface known as the Common Gateway Interface, or CGI for short.

Using JavaScript, though, you can write scripts into your HTML documents to work with form elements and their values. You already saw a basic example of this in Chapter 5, in Listing 5.3 where you produced an extremely simple calculator that calculated the value of a JavaScript expression and displayed the result.

In this section, you will take a look at each type of form element in detail and see what properties and methods and event handlers are available for each.

Table 6.2 outlines the elements that make up forms. Each element has a corresponding object.

Table 6.2. Form elements.

Form ElementDescription
button A new element that provides a button other than a submit or reset button (<INPUT TYPE="button">)
checkbox A checkbox (<INPUT TYPE="checkbox">)
FileUpload A file upload element that allows the user to provide a file as input for a form submission (<INPUT TYPE="file">)
hidden A hidden field (<INPUT TYPE="hidden">)
password A password text field in which each keystroke appears as an asterisk (*) (<INPUT TYPE="password">)
radio A radio button (<INPUT TYPE="radio">)
reset A reset button (<INPUT TYPE="reset">)
select A selection list (<SELECT><OPTION>option1</OPTION><OPTION>
option2</OPTION></SELECT>
)
submit A submit button (<INPUT TYPE="submit">)
text A text field (<INPUT TYPE="text">)
textArea A multiline text entry field (<TEXTAREA>default text</TEXTAREA>)

Each of these elements can be named and referred to by name in a JavaScript script. Each also has properties and methods associated with it.

The type Property

Before looking at each of the form element objects, let's take a look at the type property. Each of the form element objects has a type property, which is a string value reflecting the type of input element such as a button, a text field, or a checkbox.

The strings reflected by the various type properties for each form element are

The button Element

In standard HTML forms, only two buttons are available-submit and reset-because the data contained in a form must be sent to some URL (usually a CGI-BIN script) for processing or storage.

A button element is specified using the INPUT tag:

<INPUT TYPE="button" NAME="name" VALUE="buttonName">

In the above INPUT tag, a button named name is created. The VALUE attribute contains the text that the Navigator browser displays in the button.

The button element has two properties: name (as specified in the INPUT tag) and value, which is also specified in the INPUT tag.

There is a single event handler for the button element: onClick. Associated with this is a single method: click().

The addition of the button element enables JavaScript programmers to write JavaScript code to be executed for additional buttons in a script.

For instance, in Listing 5.3, instead of using the onChange element, you could alter the script as shown in Listing 6.1 to evaluate the supplied expression when a button is pressed.


Listing 6.1. Evaluating a form using the button element.
<HTML>

<HEAD>
<TITLE>button Example</TITLE>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

function calculate(form) {

  form.results.value = eval(form.entry.value);

}


// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</HEAD>

<BODY>

<FORM METHOD=POST>
Enter a JavaScript mathematical expression:
<INPUT TYPE="text" NAME="entry" VALUE="">
<BR>
The result of this expression is:
<INPUT TYPE=text NAME="results"
       onFocus="this.blur();">
<BR>
<INPUT TYPE="button" VALUE="Calculate" onClick="calculate(this.form);">
</FORM>

</BODY>

</HTML>

The checkbox Element

Checkboxes are toggle switches in an HTML form. They are used to select or deselect information. Checkboxes have more properties and methods available than buttons do, as outlined in Table 6.3.

Table 6.3. Properties and methods for the checkbox element.

Method or PropertyDescription
checked Indicates the current status of the checkbox element (property)
defaultChecked Indicates the default status of the element (property)
name Indicates the name of the element as specified in the INPUT tag (property)
value Indicates the current value of the element as specified in the INPUT tag (property)
click() Emulates a click in the checkbox (method)

As you might expect, there is a single event handler for checkboxes: onClick.

For example, you can use checkboxes to produce an alternative to the double and square exercise (Exercise 3) from Chapter 5. Instead of three fields, you can have an entry text field, a checkbox to indicate squaring (doubling will be the default action), and a results text field.

The resulting script would look like Listing 6.2.


Listing 6.2. Doubling and squaring with checkboxes.
<HTML>

<HEAD>
<TITLE>checkbox Example</TITLE>

<SCRIPT>
<!-- HIDE FROM OTHER BROWSERS

function calculate(form,callingField) {

  if (callingField == "result") {
    if (form.square.checked) {
      form.entry.value = Math.sqrt(form.result.value);
    } else {
      form.entry.value = form.result.value / 2;
    }
  } else {
    if (form.square.checked) {
      form.result.value = form.entry.value * form.entry.value;
    } else {
      form.result.value = form.entry.value * 2;
    }
  }

}

// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</HEAD>

<BODY>

<FORM METHOD=POST>

Value: <INPUT TYPE="text" NAME="entry" VALUE=0
              onChange="calculate(this.form,this.name);">
<BR>
Action (default double): <INPUT TYPE=checkbox NAME=square
onClick="calculate(this.form,this.name);">
Square
<BR>
Result: <INPUT TYPE="text" NAME="result" VALUE=0
               onChange="calculate(this.form,this.name);">

</FORM>

</BODY>

</HTML>

In this script, you see an example of how to use the onClick event handler as well as how the checked property is a Boolean value that can be used as the condition for an if … else statement.

You have added a checkbox named square to the form. If the checkbox is checked, the program will square the value. If it isn't, then the default action will be to double the value. The onClick event handler in the checkbox definition (<INPUT TYPE=checkbox NAME=square onClick="calculate(this.form,this.name);">) ensures that when the user changes the desired action, the form recalculates (as well as if the user changes the value of the entry field).

To take advantage of the checkbox, you also changed the calculate() function, as follows:

function calculate(form,callingField) {

  if (callingField == "result") {
    if (form.square.checked) {
      form.entry.value = Math.sqrt(form.result.value);
    } else {
      form.entry.value = form.result.value / 2;
    }
  } else {
    if (form.square.checked) {
      form.result.value = form.entry.value * form.entry.value;
    } else {
      form.result.value = form.entry.value * 2;
    }
  }

}

In this function, you use the Boolean property checked to determine the correct action. If form.square.checked is true, then you should be squaring; if the value is false, you should be doubling the value in the entry field.

The File Upload Element

The file upload field in a form provides a way in which users can specify a file to be included in a form submission. File upload elements are reflected in JavaScript with the FileUpload object.

The FileUpload object has only two properties associated with it: name and value, both of which are string values like other objects. There are no methods or event handlers for the FileUpload object.

The hidden Element

The hidden element is unique among all the form elements in that it is not displayed by the Web browser. Hidden fields can be used to store values that need to be sent to the server along with a form submission but that shouldn't be displayed in the page. They can also be used in JavaScript to store values used throughout a script and for calculations within a form.

The hidden object has only two properties associated with it: name and value, both of which are string values like other objects. There are no methods or event handlers for the hidden object.

The password Element

The password element is a unique type of text entry field in that any keystrokes are displayed as an asterisk (*). This makes the password element ideal for accepting input of confidential information, such as account passwords or bank account personal identification numbers (PINs).

The password object has three properties, similar to text fields: defaultValue, name, and value. Unlike the previous two elements, the password fields include more methods (focus(), blur(), and select()) and the corresponding event handlers: onFocus, onBlur, and onSelect.

We will discuss these methods and event handlers in more detail in the section on the text element.

The radio Element

The radio element is similar to toggle checkboxes, except that several radio buttons are combined into a group and only a single button can be selected at any given time. For instance, the following lines produce a group of three radio buttons named test, similar to those in Figure 6.1.

Figure 6.1 : Web a group of radio buttons, only one element can be selected at any given time.

<INPUT TYPE="radio" NAME="test" VALUE="1" chECKED>1<BR>
<INPUT TYPE="radio" NAME="test" VALUE="2">2<BR>
<INPUT TYPE="radio" NAME="test" VALUE="3">3<BR>

The group of radio buttons is formed by using a consistent name in all the INPUT tags.

The radio element is accessible in JavaScript through the radio object, which has several properties for checking the current status of a radio button group. Table 6.4 outlines the properties and methods available with the radio object.

Table 6.4. Properties and methods for the radio object.

Method or PropertyDescription
checked Indicates the current status of the radio element (property)
defaultChecked Indicates the default status of the element (property)
index Indicates the index of the currently selected radio button in the group
length Indicates the number of radio buttons in a group
name Indicates the name of the element as specified in the INPUT tag (property)
value Indicates the current value of the element as specified in the INPUT tag (property)
click() Emulates a click in the radio button (method)

As with checkboxes, the single event handler, onClick, is available for radio buttons.

The index and length properties haven't appeared in any of the form elements we have looked at so far in this chapter. Because a radio button group contains multiple elements, the radio object maintains an array of the radio buttons with indexes starting at zero. In the example of a radio button group named "test" above, if the group were part of a form named "testform", you could reference the second radio button as testform.test[1], and you could check the current status of the button with testform.test[1].checked.

To illustrate usage of the radio object, you can rewrite Listing 6.2, used to demonstrate heckboxes, using radio buttons instead.


Listing 6.3. Doubling and squaring with radio buttons.
<HTML>

<HEAD>
<TITLE>radio button Example</TITLE>

<SCRIPT>
<!-- HIDE FROM OTHER BROWSERS

function calculate(form,callingField) {

  if (callingField == "result") {
    if (form.action[1].checked) {
      form.entry.value = Math.sqrt(form.result.value);
    } else {
      form.entry.value = form.result.value / 2;
    }
  } else {
    if (form.action[1].checked) {
      form.result.value = form.entry.value * form.entry.value;
    } else {
      form.result.value = form.entry.value * 2;
    }
  }

}

// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</HEAD>

<BODY>

<FORM METHOD=POST>
Value: <INPUT TYPE="text" NAME="entry" VALUE=0
              onChange="calculate(this.form,this.name);">
<BR>
Action:<BR>
<INPUT TYPE="radio" NAME="action" VALUE="twice"
onClick="calculate(this.form,this.name);"> Double<BR>
<INPUT TYPE="radio" NAME="action" VALUE="square"
onClick="calculate(this.form,this.name);"> Square <BR>
Result: <INPUT TYPE=text NAME="result" VALUE=0
               onChange="calculate(this.form,this.name);">

</FORM>

</BODY>

</HTML>

In this example, the changes from the checkbox version are subtle. Instead of one checkbox, you now have a pair of radio buttons with different values: double and square.

You know that the individual radio buttons are accessible through an array so that the double button is action[0] and the square button is action[1]. In this way, you need to change only the references in the calculate() function from form.square.checked to form.action[1].checked.

The reset Element

Using the reset object in JavaScript, you can react to clicks on the Reset button. Like the button object, the reset object has two properties (name and value) and one method (click()). The onClick event handler is also available.

Note
A bug in Navigator 2 results in odd behavior with the Reset button: When text fields are cleared by the Reset button, this isn't reflected into the corresponding element until the field is given focus.

Although most programmers do not find a need to use the onClick event handler for reset buttons or need to check the value of the button, the reset object can be used to clear the form to some value other than the default.

Listing 6.4. demonstrates how the Reset button can be used to clear a form to values other than the default.


Listing 6.4. Clearing a form to new values with Reset.
<HTML>

<HEAD>
<TITLE>reset Example</TITLE>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

function clearForm(form) {

  form.value1.value = "Form";
  form.value2.value = "Cleared";

}

// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</HEAD>

<BODY>

<FORM METHOD=POST>
<INPUT TYPE="text" NAME="value1"><BR>
<INPUT TYPE="text" NAME="value2"><BR>
<INPUT TYPE="reset" VALUE="Clear Form" onClick="clearForm(this.form);">

</FORM>

</BODY>

</HTML>

This script is fairly simple. You have created a form with two text fields and a Reset button. The Reset button has an onClick event handler, which calls clearForm() when the button is clicked.

The clearForm() function takes the form object as an argument and proceeds to place two new values in the two text fields of the form.

The select Element

Selection lists in HTML forms appear as drop-down menus or scrollable lists of selectable items. Lists are built using two tags: SELECT and OPTION. For instance, the following code snippet

<SELECT NAME="test">
<OPTION SELECTED>1
<OPTION>2
<OPTION>3
</SELECT>

creates a three-item, drop-down menu with the choices 1, 2, and 3. Using the SIZE attribute you can create a scrollable list with the number of elements visible at one time indicated by the value of the SIZE attribute. To turn your drop-down menu into a scrollable menu with two visible items you could use the following:

<SELECT NAME="test" SIZE=2>
<OPTION SELECTED>1
<OPTION>2
<OPTION>3
</SELECT>

In both of these examples, the user can make only one choice. Using the MULTIPLE attribute, you can enable the user to select more than one choice in a scrollable selection list:

<SELECT NAME="test" SIZE=2 MULTIPLE>
<OPTION SELECTED>1
<OPTION>2
<OPTION>3
</SELECT>

Selection lists are accessible in JavaScript through the select object. This object bears some similarity to both the buttons you have seen, as well as with radio buttons.

As with radio buttons, the list of options is maintained as an array with indexes starting at zero. In this case, the array is a property of the select object called options.

Both selection option and the individual option elements have properties. In addition to the options array, the select object has the selectedIndex property, which contains the index number of the currently selected option.

Each option in a selection list also has several properties. defaultSelected indicates whether the option is selected by default in the OPTION tag. The index property contains the index value of the current option in the options array. Again, as you might expect, selected indicates the current status of the option, text contains the value of the text displayed in the menu for the specific option, and value contains any value indicated in the OPTION tag.

The select object has no available methods. However, the select object has three event handlers that don't correspond to the available event emulating method. These are onBlur, onFocus, and onChange-the same as for the text object.

Note
In the current version of JavaScript, the onChange event handler is not invoked immediately after the user changes his selection. Rather, once the user leaves the selection list (that is, removes focus from the list), then the onChange event handler works.

For example, if you have the following selection list:

<SELECT NAME="example" onFocus="react();">
<OPTION SELECTED VALUE="Number One">1
<OPTION VALUE="The Second">2
<OPTION VALUE="Three is It">3
</SELECT>

then when the list is first displayed, you would have access to the following information:

example.options[1].value = "The Second"

example.options[2].text = "3"

example.selectedIndex = 0

example.options[0].defaultSelected = true

example.options[1].selected = false

If the user then clicks on the menu and selects the second option, the onFocus event handler would execute (the react() function would be called), and then the values of these same properties would be as follows:

example.options[1].value = "The Second"

example.options[2].text = "3"

example.selectedIndex = 1

example.options[0].defaultSelected = true

example.options[1].selected = true

Modifying Select Lists

In Navigator 3.0, it is possible to change the content of a select list from inside JavaScript by assigning new values to the list entries' text property.

For instance, in the example earlier where you created the following selection list,

<SELECT NAME="example" onFocus="react();">
<OPTION SELECTED VALUE="Number One">1
<OPTION VALUE="The Second">2
<OPTION VALUE="Three is It">3
</SELECT>

it would be possible to change the text displayed for the second entry to "two" with

example.options[1].text = "two";

New options can be added to the list using the Option() constructor object with the syntax:

newOptionName = new Option(optionText, optionValue, defaultSelected, selected);
selectListName.options[index] = newOptionName;

This creates an option object with the specified text and the defaultSelected and selected states for the option specified as Boolean values. This object is then assigned to an entry in the selection list specified by index.

Options can be deleted from the option list by assigning null to the option object for the particular entry:

selectListName.options[index] = null;

The submit Element

The Submit button is another special-purpose button like the Reset button. This button submits the current information from each field of the form to the URL specified in the ACTION attribute of the FORM tag using the METHOD indicated in the FORM tag.

Like with the button object and the reset object, you have name and value properties available to you, along with a click() method and an onClick event handler.

The text Element

text elements are among the most common entry fields used in HTML forms. Similar to the password field you looked at earlier, text fields enable a single line of text entry, but unlike the password element, the text is displayed as normal type rather than as asterisks.

The text object has three properties: defaultValue, name, and value. Three methods emulate user events: focus(), blur(), and select() (which selects the text in the entry field). Four event handlers are available: onBlur, onFocus, onChange, and onSelect (for when the user selects some of the text in the field).

Table 6.5 outlines the properties and methods for the text element.

Table 6.5. Properties and methods for the text object.

Method or PropertyDescription
defaultValue Indicates the default value of the element as specified in INPUT tag (property)
name Indicates the name of the element as specified in the INPUT tag (property)
value Indicates the current value of the element (property)
focus() Emulates giving focus to the text field (method)
blur() Emulates removing focus from the text field (method)
select() Emulates selecting text in the text field (method)

It is important to note that the content of a text field can be changed by assigning values to the value property. Thus, in the following example, text entered in the first field is echoed in the second field, and any text entered in the second field is echoed in the first field. By itself, this has little value, but the ability to use data from a text field and to dynamically update and change data in a text field is a powerful feature of JavaScript as shown in Listing 6.5.


Listing 6.5. Dynamically updating text fields.
<HTML>

<HEAD>
<TITLE>text Example</TITLE>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

function echo(form,currentField) {

  if (currentField == "first")
    form.second.value = form.first.value;
  else
    form.first.value = form.second.value;

}

// STOP HIDING FROM OTHER BROWSERS -->

</SCRIPT>

</HEAD>

<BODY>

<FORM>
<INPUT TYPE=text NAME="first" onChange="echo(this.form,this.name);">
<INPUT TYPE=text NAME="second" onChange="echo(this.form,this.name);">
</FORM>

</BODY>

</HTML>

Note
In versions of Navigator 2.0, the onChange event handler is not invoked as soon as the user types a change. Rather, it is invoked when focus leaves the field and the text has changed.

The textarea Element

The TEXTAREA tag provides a custom size multiple-line text entry field defined by a container. The example in this code

<TEXTAREA NAME="fieldName" ROWS=10 COLS=25>
Default Text Here
</TEXTAREA>

creates a text entry field of 10 rows with 25 characters on each line. The words Default Text Here would appear in the field when it is first displayed.

Like the text element, JavaScript provides you with the defaultValue, name, and value properties, the focus(), blur(), and select() methods and the onBlur, onFocus, onChange, and onSelect event handlers.

Using Tables to Create a Calculator

Now that we have taken a detailed look at the form object, its elements, properties, and methods, you are ready to use this information to build a somewhat more complicated script.

In this example, you will build a simple mathematical calculator using forms. That is, each number and the four mathematical functions (addition, subtraction, multiplication, and division) will each be a button. You will also have two other buttons: one to clear the running total and the other to clear the current entry.

In order to make your calculator appear more organized, you will make use of HTML tables. For those without experience using tables, tables are contained in the TABLE container tag and consist of rows contained in the TR tag and column elements contained in the TD tag. In addition, the COLSPAN attribute causes a cell to cover two columns. Similarly, ROWSPAN makes a cell two rows deep.

Note
A more detailed discussion of HTML tables is available at Netscape's Web site at the URL: http://home.netscape.com/assist/net_sites/tables.html.

For instance, the HTML code in Listing 6.6 produces a simple table.


Listing 6.6. A simple table.
<TABLE BORDER=1>
<TR>
<TD COLSPAN=2>This is a table</TD>
</TR>
<TR>
<TD>One</TD>
<TD>Two</TD>
</TR>
<TR>
<TD>Three</TD>
<TD>Four</TD>
</TR>
</TABLE>

The output from Listing 6.6 looks like the one in Figure 6.2.

Figure 6.2 : HTML tables contain rows and columns of cells.

Using tables, then, you are ready to work on developing your calculator.

In terms of behavior, your calculator should work the way a simple electronic calculator does: When a user enters a number, it is immediately displayed to the right of previously entered digits. Mathematical functions are executed in the order entered (no precedence here), and the effects of operations are cumulative until the clear button is pressed. Listing 6.7 is the source code for this calculator.


Listing 6.7. Creating a calculator with tables.
<HTML>

<HEAD>
<TITLE>Example 6.7</TITLE>

<SCRIPT>
<!-- HIDE FROM OTHER BROWSERS

var total = 0;
var lastOperation = "+";
var newnumber = true;

function enterNumber(digit) {

  var form = digit.form;

  if (newnumber) {
    clearNumber(form);
    newnumber = false;
  }

  form.display.value = form.display.value + digit.name;

}

function clear(form) {

  total = 0;
  lastOperation = "+";
  form.display.value = "";

}

function clearNumber(form) {

  form.display.value = "";

}

function calculate(operation) {

  var form = operation.form;

  var expression = total + lastOperation + form.display.value;

  lastOperation = operation.value;
  total = eval(expression);
  form.display.value = total;
  newnumber = true;

}

// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</HEAD>

<BODY>

<FORM>

<TABLE BORDER=1>

<TR>
<TD COLSPAN=4>
<INPUT TYPE=text NAME=display VALUE="" onFocus="this.blur();">
</TD>
</TR>

<TR>
<TD>
<INPUT TYPE=button NAME="7" VALUE=" 7 " onClick="enterNumber(this);">
</TD>
<TD>
<INPUT TYPE=button NAME="8" VALUE=" 8 " onClick="enterNumber(this);">
</TD>
<TD>
<INPUT TYPE=button NAME="9" VALUE=" 9 " onClick="enterNumber(this);">
</TD>
<TD>
<INPUT TYPE=button NAME="+" VALUE=" + " onClick="calculate(this);">
</TD>
</TR>

<TR>
<TD>
<INPUT TYPE=button NAME="4" VALUE=" 4 " onClick="enterNumber(this);">
</TD>
<TD>
<INPUT TYPE=button NAME="5" VALUE=" 5 " onClick="enterNumber(this);">
</TD>
<TD>
<INPUT TYPE=button NAME="6" VALUE=" 6 " onClick="enterNumber(this);">
</TD>
<TD>
<INPUT TYPE=button NAME="-" VALUE="  -  " onClick="calculate(this);">
</TD>
</TR>

<TR>
<TD>
<INPUT TYPE=button NAME="1" VALUE=" 1 " onClick="enterNumber(this);">
</TD>
<TD>
<INPUT TYPE=button NAME="2" VALUE=" 2 " onClick="enterNumber(this);">
</TD>
<TD>
<INPUT TYPE=button NAME="3" VALUE=" 3 " onClick="enterNumber(this);">
</TD>
<TD>
<INPUT TYPE=button NAME="*" VALUE=" * " onClick="calculate(this);">
</TD>
</TR>

<TR>
<TD>
<INPUT TYPE=button NAME="0" VALUE=" 0 " onClick="enterNumber(this);">
</TD>
<TD>
<INPUT TYPE=button NAME="C" VALUE=" C " onClick="clear(this.form);">
</TD>
<TD>
<INPUT TYPE=button NAME="CE" VALUE="CE" onClick="clearNumber(this.form);">
</TD>
<TD>
<INPUT TYPE=button NAME="/" VALUE="  /  " onClick="calculate(this);">
</TD>
</TR>

</TABLE>

</FORM>

</BODY>

</HTML>

This script produces results like those in Figure 6.3.

Figure 6.3 : Tables make the calculator look appealing, and JavaScript makes it work.

Several interesting techniques are used in this script. Let's take a look at selected parts of the script sequentially from the start.

var total = 0;
var lastOperation = "+";
var newnumber = true;

Here you declare the global variables to keep track of information. The total variable contains the current running total of the user's calculations. This is the same as the last displayed value before the user began entering a new number. lastOperation is used to keep track of the operation last entered by the user to be performed on the running total and the newly entered number. newnumber is used to keep track of when user input should be treated as a new number or part of the currently displayed number.

The initial values of these variables require some explanation. Obviously, total starts with a zero value. However, as you will see later in the calculate() function, you need a lastOperation value to perform on every number entered. By assigning the value "+" to lastOperation, the first number entered by the user will be added to the initial total of zero.

function enterNumber(digit) {

  var form = digit.form;

  if (newnumber) {
    clearNumber(form);
    newnumber = false;
  }

  form.display.value = form.display.value + digit;



}

You pass the currently clicked button object to enterNumber() as the argument digit. The line var form = digit.form; provides you with reference to the form containing the current button in much the same way as when you pass this.form to a function.

Because each new digit is added to the right side of the number, you can treat the digits as strings to concatenate.

function calulate(operation) {

  var form = operation.form;

  var expression = total + lastOperation + form.display.value;

  lastOperation = operation.value;
  total = eval(expression);
  form.display.value = total;
  newnumber = true;

}

The calculate() function is where the real work of the calculator script is done. The function is invoked when the user clicks on one of the operator buttons. When this happens, the line var expression = total + lastOperation + form.display.value; builds an expression in the form of a string.

You then use the eval() function to evaluate the expression you have just built. This value becomes the new value of total, is displayed in the text field, and the operation the user has just clicked is assigned to lastOperation.

One component of this calculator that is lacking is an equal ( = ) button. To implement it would require changing the logic of the calculate() function.

The elements[] Array

As mentioned in the section on the properties of the form object, all the elements in a form can also be referenced by the elements[] array. For instance, you could create the following form:

<FORM METHOD=POST NAME=testform>
<INPUT TYPE="text" NAME="one">
<INPUT TYPE="text" NAME="two">
<INPUT TYPE="text" NAME="three">
</FORM>

You can refer to the three elements as document.testform.elements[0], document.testform.elements[1], and document.testform.elements[2] in addition to the obvious document.testform.one, document.testform.two, document.testform.three.

This can be useful in situations where the sequential relationship of form elements is more important than their names.

Building a Multiplication Table

In this example, you will take advantage of the elements[] array to build a simple dynamic multiplication table. The form will have 11 elements. The user fills in the first field to specify which multiplication table to calculate, and the rest of the fields provide the 1 to 10 multiplication table for that number.


Listing 6.8. Using the elements[] array in a multiplication table.
<HTML>

<HEAD>
<TITLE>Example 6.8</TITLE>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

function calculate(form) {

  var num=1;
  var number=form.number.value;
  form.elements[num].value = number * num++;
  form.elements[num].value = number * num++;
  form.elements[num].value = number * num++;
  form.elements[num].value = number * num++;
  form.elements[num].value = number * num++;
  form.elements[num].value = number * num++;
  form.elements[num].value = number * num++;
  form.elements[num].value = number * num++;
  form.elements[num].value = number * num++;
  form.elements[num].value = number * num++;

}

// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</HEAD>

<BODY>

<FORM METHOD=POST>
Number: <INPUT TYPE=text NAME="number" VALUE=1
onChange="calculate(this.form);"><BR>
x 1: <INPUT TYPE=text NAME="1" VALUE=1 onFocus="blur();"><BR>
x 2: <INPUT TYPE=text NAME="2" VALUE=2 onFocus="blur();"><BR>
x 3: <INPUT TYPE=text NAME="3" VALUE=3 onFocus="blur();"><BR>
x 4: <INPUT TYPE=text NAME="4" VALUE=4 onFocus="blur();"><BR>
x 5: <INPUT TYPE=text NAME="5" VALUE=5 onFocus="blur();"><BR>
x 6: <INPUT TYPE=text NAME="6" VALUE=6 onFocus="blur();"><BR>
x 7: <INPUT TYPE=text NAME="7" VALUE=7 onFocus="blur();"><BR>
x 8: <INPUT TYPE=text NAME="8" VALUE=8 onFocus="blur();"><BR>
x 9: <INPUT TYPE=text NAME="9" VALUE=9 onFocus="blur();"><BR>
x 10: <INPUT TYPE=text NAME="10" VALUE=10 onFocus="this.blur();"><BR>
<ITEM TYPE=button NAME="calculcate" VALUE="Calculate"
onClick="calculate(this.form);">
</FORM>


</BODY>

</HTML>

Listing 6.8 produces results similar to those in Figure 6.4.

Figure 6.4 : Using the elements[ ] array, you can reference each field in order.

Notice in this script that you can refer to form elements by number. Because the elements[] array starts with an index of zero, you have made the first element (index zero) the entry field and have started the multiplication table with element two (which has an index value of one).

In the function calculate(), you use the variable num as a counter which starts at one. You use the following command 10 times to build the multiplication table:

form.elements[num].value = number * num++;

What this line tells you to do is assign the value of number * num to the current element and then increase num by one. This provides an excellent example of how to use the unary increment operator (++) to return the value of an expression and then increase it by one.

Typically, you would not write the calculate() function the way you have here. Instead, you would use a for loop:

function calculate(form) {

  var number=form.number.value;
  for(num = 1; num <= 10; num++) {
    form.elements[num].value = number * num;
  }

}

for loops are covered in Chapter 7, "Loops."

The forms[] Array

While event handlers are generally designed to work with individual forms or fields, at times, it is useful to be able to reference forms in relationship to other forms on a page.

This is where the document.forms[] array comes into play. It would be possible to have multiple identical forms on the same page and have information in a single field match in all three forms. This could be more easily achieved using the document.forms[] array than with form names. In this script, you have two text entry fields in separate forms. Using the forms[] array, you keep the value of the fields in each form the same when the user changes a value in one form.

<HTML>

<HEAD>
<TITLE>forms[] Example</TITLE>
</HEAD>

<BODY>

<FORM METHOD=POST>
<INPUT TYPE=text onChange="document.forms[1].elements[0].value = this.value;">
</FORM>

<FORM METHOD=POST>
<INPUT TYPE=text onChange="document.forms[0].elements[0].value = this.value;">
</FORM>

</BODY>

</HTML>

In addition to referring to forms numerically in the forms[] array, they can also be refereed to by name. Using the NAME attribute of the FORM tag, you can assign a name to a form:

<FORM METHOD=POST NAME="name">

Then, this form can be referred to as document.forms["name"] or as document.name.

Prompting with Text Fields

Now you are going to put together some of the skills you have learned in this chapter in a different type of interactive form.

Usually, text entry forms consist of field names followed by fields. What you want to do is produce forms where the field name (that is, the prompt for the field) is the initial value of the field. This should look like the example in Figure 6.5.

Figure 6.5 : Prompt information as a field's default value looks less cluttered on landegg Academy's home page.

If the user clicks in an unchanged field, the field clears and the user enters information. If he moves the focus out of the field and hasn't entered any information, the original content reappears.

At the same time, if the user clicks in a field that contains data entered by the user, the field is not cleared.

This can be done by developing a general-purpose set of functions, such as those in Listing 6.9.


Listing 6.9. An interactive entry form.
<HTML>

<HEAD>