Chatper 6
Using Interactive Forms
CONTENTS
In this chapter you'll explore one of the most powerful uses for
JavaScript: working with HTML forms. You can use JavaScript to
make a form more interactive, to validate data the user enters,
and to enter data based on other data.
Let's begin with a basic order form for an imaginary company and
use JavaScript to add features to the form. Along the way you'll
learn about the various form elements, how they relate to JavaScript,
and just what you can do with each one.
HTML started out as a read-only language; you could present information
to readers and allow them to follow links to sites with different
information, but there was no way to accept input from the user.
The advent of HTML forms changed things considerably. Forms added
new HTML tags that could take input from the user. This enables
you easily to create a fill-out form to register users or take
orders, or for any other purpose.
Before you build a sample form, let's start with a quick overview
of the elements you can use in a form. Each of these will relate
to a JavaScript object, which is discussed later in this chapter.
By itself, an HTML form can only hold information; it can't send
it to the server. This part of the job is accomplished by Common
Gateway Interface (CGI), a standard for server-side applications.
When you press the SUBMIT button on a form, the data in the fields
is sent to the CGI program, which can act on the data-mail you
a response, send a result back to the user, or add an item to
a database.
When you submit the form data, it is sent to the server using
one of two methods:
- The GET method places
the data in the URL itself.
- The POST method sends
the data as a block of input.
You'll learn about the technical aspects of these methods and
which you should use in Chapter 17, "Combining JavaScript,
CGI, and SSI." Basically, it will depend on the data and
on what the CGI script you are using supports. For the moment,
you can use either one.
Because JavaScript can't communicate with the server, it doesn't
eliminate the need for CGI; instead, it enables you to control
the data as it is entered and check it for accuracy before the
CGI program receives it. This saves you work creating the CGI
program. In fact, you can easily use the same CGI program for
many different forms. One such script is presented in Chapter
17.
Tip |
It is possible to have a JavaScript-only form. You used simple forms in Chapter 5 "Accessing Window Elements as Objects," to interact with the user. You'll find many more examples throughout this guide.
|
After the CGI script receives the data, it sends a response back
to the user. This can send the user to a different Web page or
can generate a page "on the fly" and display it.
An HTML form begins with the <FORM>
tag. This tag indicates that a form is beginning, and it enables
form elements to be used. The <FORM>
tag includes three parameters:
- NAME is simply a name
for the form. You can use forms without giving them names, but
you'll need to assign a name in order to use the form with JavaScript.
- METHOD is either GET
or POST; these are the two
ways the data can be sent to the server.
- ACTION is the CGI script
that the form data will be sent to when submitted. You'll look
at an actual script in Chapter 17. You can also use the mailto:
action to send the form's results to an e-mail address.
For example, here is a <FORM>
tag for a form named Order.
This form uses the GET method
and sends its data to a CGI script called order.cgi
in the same directory as the Web page itself:
<FORM NAME="Order" METHOD="GET" ACTION="order.cgi">
For a form that will be processed entirely by JavaScript (such
as a calculator or interactive game), the METHOD
and ACTION attributes are
not needed. You can use a simple <FORM>
tag that names the form:
<FORM NAME="calcform">
The <FORM> tag is followed
by one or more form elements. These are the data fields in the
form, such as text fields and checkboxes. You will look at each
type of element in the following sections. After all the elements
comes the form ending tag, </FORM>.
After this tag, you can't use form elements without starting another
form.
Note |
You can also include any normal HTML elements within the <FORM> tags. This is useful for labeling each of the elements.
|
Text Fields and Text Areas
Many of the form elements use the <INPUT>
tag. This tag is followed by a TYPE
parameter to determine which type of input is expected. The first
such field is the TEXT field.
This is the simplest of the form elements; it enables the user
to enter text in a one-line area. The following is an example
of a simple TEXT field:
<INPUT TYPE="TEXT" NAME="text1" VALUE="hello" SIZE="30">
This defines a text field called text1.
The field is given a default value of "hello"
and allows up to 30 characters to be entered.
An alternate form of text field is the PASSWORD
field. This is a specialized text field that displays the text
as asterisks on the screen. This type of input is often used for
passwords so that observers don't see which password is being
entered. The password field is defined like TEXT:
<INPUT TYPE="PASSWORD" NAME="pass1" SIZE=30>
A third option is the text area, which allows multiple lines of
text to be entered. Rather than using the <INPUT>
tag, text areas are defined with a special tag, <TEXTAREA>.
Here is a typical <TEXTAREA>
definition:
<TEXTAREA NAME="text1" ROWS="2" COLS="70">
This is the content of the TEXTAREA tag.
</TEXTAREA>
The text between the opening and closing <TEXTAREA>
tags is used as the initial value for the text area. This type
of tag is ideal when you need a larger amount of information,
such as a complete address or a paragraph of text. You can include
line breaks within the default value.
Figure 6.1 shows examples of TEXT,
PASSWORD, and TEXTAREA
tags on an HTML page, as displayed by Netscape.
Figure 6.1 : An example of the TEXT,
PASSWORD, and TEXTAREA
form elements.
Checkboxes, Radio Buttons, and Selection Lists
For some parts of your form, you may want to ask simple questions:
yes/no questions, multiple-choice questions, and so on. Three
form elements make it easy to do this.
The first element is the checkbox; this simply displays a box
that can be checked or unchecked. The chECKBOX
type to the INPUT tag is
used to create a checkbox, as follows:
<INPUT TYPE="chECKBOX" NAME="check1" VALUE="Yes" chECKED>
Again, this gives a name to the form element. The VALUE
attribute assigns a meaning to the checkbox; this is a value that
is returned if the box is checked. The default value is "on."
Finally, the chECKED attribute
can be included to make the box checked by default.
Another element for decisions is the radio button, using the <INPUT>
tag's RADIO type. These buttons
are similar to checkboxes, but they exist in groups, and only
one button can be checked in each group. These are used for a
multiple-choice or "one of many" input. Here's an example
of a group of radio buttons:
<INPUT TYPE="RADIO" NAME="radio1" VALUE="Option1" chECKED> Option 1
<INPUT TYPE="RADIO" NAME="radio1" VALUE="Option2"> Option 2
<INPUT TYPE="RADIO" NAME="radio1" VALUE="Option3"> Option 3
Once again, the NAME attribute
is used; in this case, it names the entire group of radio buttons.
All the buttons with the same name are considered to be in a group.
The VALUE attribute gives
each button a name; this is essential so that you can tell which
one is pressed.
A final form element is also useful for multiple-choice selections:
the <SELECT> HTML tag
is used to define a selection list, or a multiple-choice
list of text items. This is an example of a selection list:
<SELECT NAME="select1" SIZE=40>
<OPTION VALUE="choice1" SELECTED>This is the first choice.
<OPTION VALUE="choice2">This is the second choice.
<OPTION VALUE="choice3">This is the third choice.
</SELECT>
Each of the OPTION tags defines
one of the possible choices. The VALUE
attribute is the name that is returned to the program, and the
text outside the OPTION tag
is displayed as the text of the option.
An optional attribute to the SELECT
tag, MULTIPLE, can be specified
to allow multiple items to be selected. Browsers usually display
a single-selection SELECT
as a drop-down list and a multiple-selection list as a scrollable
list.
Figure 6.2 is an example of an HTML page in Netscape that shows
examples of checkboxes, radio buttons, and single- and multiple-selection
lists.
Figure 6.2 : An example of the display of checkboxes,
radio buttons, and selection lists.
Hidden Fields
HTML form elements include a special type of field: the hidden
field. This includes a name and a value, similar to a text field;
however, you can't edit it, and it is not displayed on the Web
page. Hidden fields are useful for passing information to the
CGI script or between multiple scripts.
A hidden field uses the <INPUT>
tag and simply has a name and a value. For example, this command
defines a hidden field called score
with a value of 40200:
<INPUT TYPE="HIDDEN" NAME="score" VALUE="40200">
SUBMIT and RESET Buttons
The final type of form element is a button. Buttons use the <INPUT>
tag and can use one of three different types:
- type=SUBMIT is a submit
button. This button causes the data in the form fields to be sent
to the CGI script.
- type=RESET is a reset
button. This button sets all the form fields back to their default
value, or blank.
- type=BUTTON is a generic
button. This button performs no action on its own, but you can
assign it one using JavaScript.
All three types of buttons include a NAME
to identify the button, and a VALUE
that indicates the text to display on the button's face. A few
buttons were used in the examples in Chapter 5. As an example,
the following defines a SUBMIT
button with the name sub1
and the value "Click Here":
<INPUT TYPE="SUBMIT" NAME="sub1" VALUE="Click Here">
Using the form elements discussed, let's create an order form
for a fictional software company called, coincidentally enough,
Fictional Software Company (FSC). This company sells four products:
a word processor, a spreadsheet, a database, and an instruction
guidelet. You will use the following elements:
- Text fields for the buyer's name, phone number, and e-mail
address, and text areas for the billing and shipping address.
- Because the company has only four products, there's room to
list them all on the form. Each has its own text fields for quantity
and cost.
- A total cost text field is used to store the total cost. The
user then selects the method of payment from the selection list
and enters a credit card number or check number if needed.
- Finally, a SUBMIT button enables users to send the order,
and a RESET button enables them to start over with the defaults.
Listing 6.1 shows the complete HTML form, and Figure 6.3 shows
Netscape's display of the form.
Figure 6.3 : The first draft of the FSC order form.
Listing 6.1. The HTML document for the order form.
<HTML>
<HEAD><TITLE>Order Form</TITLE></HEAD>
<BODY>
<H1>Order Form</H1>
<FORM NAME="order">
<B>Name:</B> <INPUT TYPE="text" NAME="name1" SIZE=20>
<B>Phone: </B><INPUT TYPE="text" NAME="phone" SIZE=15>
<B>E-mail address:</B><INPUT TYPE="text" NAME="email" SIZE=20><BR>
<B>Billing and Shipping Addresses:</B><BR>
<TEXTAREA NAME="billto" COLS=40 ROWS=4>
Enter your billing address here.
</TEXTAREA>
<TEXTAREA NAME="shipto" COLS=40 ROWS=4>
Enter your shipping address here.
</TEXTAREA>
<B>Products to Order:</B><BR>
Qty: <INPUT TYPE="TEXT" NAME="qty1" VALUE="0" SIZE=4>
Cost: <INPUT TYPE="TEXT" NAME="cost1" SIZE=6>
($40.00 ea) Fictional Spreadsheet 7.0 <BR>
Qty: <INPUT TYPE="TEXT" NAME="qty2" VALUE="0" SIZE=4>
Cost: <INPUT TYPE="TEXT" NAME="cost2" SIZE=6>
($69.95 ea) Fictional Word Processor 6.0<BR>
Qty: <INPUT TYPE="TEXT" NAME="qty3" VALUE="0" SIZE=4>
Cost: <INPUT TYPE="TEXT" NAME="cost3" SIZE=6>
($99.95 ea) Fictional Database 7.0 <BR>
Qty: <INPUT TYPE="TEXT" NAME="qty4" VALUE="0" SIZE=4>
Cost: <INPUT TYPE="TEXT" NAME="cost4" SIZE=6>
($4.95 ea) Instruction guidelet for the above <HR>
<B>Total Cost:</B>
<INPUT TYPE="TEXT" NAME="totalcost" SIZE=8><HR>
<B>Method of Payment</B>:
<SELECT NAME="payby">
<OPTION VALUE="check" SELECTED>Check or Money Order
<OPTION VALUE="cash">Cash or Cashier's Check
<OPTION VALUE="credit">Credit Card (specify number)
</SELECT><BR>
<B>Credit Card or Check Number:</B>:
<INPUT TYPE="TEXT" NAME="creditno" SIZE="20"><BR>
<INPUT TYPE="SUBMIT" NAME="submit" VALUE="Send Your Order">
<INPUT TYPE="RESET" VALUE="Start Over">
</FORM>
</BODY>
</HTML>
Forms like this one are used all over the Web. As you can see,
this form isn't very user-friendly; the user has to calculate
the cost for each item and the total cost. You will use JavaScript
to add automatic calculation and other interactive features later
in this chapter.
Before you continue working with the order form, let's look at
the way JavaScript handles form data. Each form in your HTML page
is represented in JavaScript by a form
object. The form object has
the same name as the NAME
attribute in the <FORM>
tag you used to define it.
Alternately, you can use the forms
array to refer to forms. This array includes an item for each
form element, indexed starting with zero. For example, if the
first form in a document has the name form1,
you can refer to it in one of two ways:
document.form1
document.forms[0]
The most important property of the form
object is the elements array,
which contains an object for each of the form elements. You can
refer to an element by its own name or by its index in the array.
For example, these expressions both refer to the first element
in the order form, the name1
text field:
document.order.elements[0]
document.order.name1
Note |
Both forms and elements can be referred to with their own names, or as indices in the forms and elements arrays. For clarity, this chapter will use individual form and element names rather than array references.
|
If you do refer to forms and elements as arrays, you can use the
length property to determine
the number of objects in the array: document.forms.length
is the number of forms in a document, and document.form1.elements.length
is the number of elements in the form1
form.
Along with the elements, each form
object also has a list of properties, most of which are defined
by the corresponding <FORM>
tag. You can also set these from within JavaScript. They include
the following:
- action is the form's
ACTION attribute, or the
program to which the form data will be submitted.
- encoding is the MIME
type of the form, specified with the EncTYPE
attribute. In most cases, this is not needed.
- length is the number
of elements in the form.
- method is the method
used to submit the form, either GET
or POST.
- target specifies the
window in which the result of the form (from the CGI script) will
be displayed. Normally, this is done in the main window, replacing
the form itself.
The form object has two event
handlers, onSubmit and onReset.
You can specify a group of JavaScript statements or a function
call for these events within the <FORM>
tag that defines the form.
If you specify a statement or function for the onSubmit
event, the statement is called before the data is submitted to
the CGI script. You can prevent the submission from happening
by returning a value of false
from the onSubmit event handler.
If the statement returns true,
the data will be submitted. In the same fashion, you can prevent
a RESET button from working with an onReset
event handler.
The form object has two methods,
submit() and reset().
You can use these methods to submit the data or reset the form
yourself, without requiring the user to press a button. The submit()
method should be used only in special cases; it's generally bad
manners to send data to the server without the user's permission.
Note |
You can use a mailto URL in the ACTION attribute of a form and have the data mailed to you instead of submitted to a CGI script. Using the submit() method with such an action enabled scripts to obtain information about your
computer or to send mail from your address without your knowledge. Because of this potential security and privacy concern, Netscape disabled the submit method for mailto URLs.
|
The elements of a form each have their own object classes, and
each of these has certain properties, methods, and events. In
the next sections, you will look at each type of JavaScript object
used for form elements in detail.
One property applies to all form elements: the type
property is a string that describes the type of element. For most
of the elements, this is the value you specified in the TYPE
attribute of the <INPUT>
tag. The exceptions are the following:
- For text areas (defined with <TEXTAREA>),
the type is "textarea".
- For single selection lists (defined with <SELECT>),
the type is "select-one".
- For selection lists that include the MULTIPLE
attribute, the type is "select-multiple".
Another property that applies to all form
elements is the form property,
which indicates an element's parent form
object.
Text fields are the simplest field to work with in JavaScript.
Password fields are nearly identical; the main difference is that
the text is not displayed. The text
and password objects have
the following properties:
- name is the name given
to the field. This is also used as the object name.
- defaultValue is the default
value; this corresponds to the VALUE
attribute. This is a read-only property.
- value is the current
value. This starts out the same as the default value, but can
be changed-either by the user or by JavaScript functions.
Most of the time when you work with text fields, you will use
the value attribute to read
the value the user has entered, or to change the value. For example,
this statement changes the value of a text field called username
in the order form to "John
Q. User":
document.order.username.value = "John Q. User"
Note |
For security reasons, you cannot normally access the value property of a password object in JavaScript. You can access it if you enable data tainting, as explained in Chapter 10, "Working with Multiple Pages
and Data."
|
Text Field Methods
The text and password
objects also have a few methods you can use:
- focus() sets the focus
to the field. This positions the cursor in the field and makes
it the "current" field.
- blur() is the opposite;
it removes the focus from the field.
- select() selects the
text in the field, just as a user can do with the mouse. You cannot
currently select only part of a field.
Tip |
These aren't the only methods you can use with text fields; don't forget that because the value property is a String object, you can use any of the String methods on the value. The String object is explained in Chapter 4 "Using Built-In Objects and Custom Objects."
|
Text Field Events
The text and password
objects support the following event handlers:
- The onFocus event happens
when the text field gains focus.
- The onBlur event happens
when the text field loses focus.
- The onChange event happens
when the user changes the text in the field, then moves out of
it.
- The onSelect event happens
when the user selects some or all of the text in the field. Unfortunately,
there's no way to tell exactly which part of the text was selected.
If used, these event handlers should be included in the <INPUT>
tag declaration. For example, the following is a text field including
an onChange event that displays
an alert:
<INPUT TYPE="TEXT" NAME="text1" onChange="window.alert('Changed.');">
Text areas are defined with their own tag, <TEXTAREA>,
and are represented by the textarea
object. This object includes the same properties, methods, and
event handlers as the text
and password objects. For
example, this <TEXTAREA>
tag includes an onFocus event
handler to change the status line:
<TEXTAREA NAME="text2" onFocus = "window.status = 'got focus.';">Default Value</TEXTAREA>
There is one difference about a text area's value: it can include
more than one line, with end-of-line characters between. This
can be complicated by the fact that the end-of-line character
is different on the three platforms (\r\n
in Windows; \n in UNIX and
Macintosh). Be sure to check for both types when needed.
If you are placing your own values into a text field, the latest
version of JavaScript automatically converts any end-of-line characters
to match the user's platform, so you can use either type.
Note |
This is an example of a platform-specific issue within JavaScript; although JavaScript is intended as a platform-independent language, there are still a few stubborn features. See Chapter 14, "Debugging JavaScript
Programs," for additional information.
|
A checkbox is simple: it has only two states. Nevertheless, the
checkbox object has four different properties:
- name is the name of the
checkbox, and also the object name.
- value is the "true"
value for the checkbox-usually on.
This value is used by the server to indicate that the checkbox
was checked. In JavaScript, you should use the checked
property instead.
- defaultChecked is the
default status of the checkbox, assigned by the chECKED
attribute.
- checked is the current
value (true for checked, and false for unchecked).
To manipulate the checkbox or use its value, you use the checked
attribute. For example, this statement turns on a checkbox called
same in the order
form:
document.order.same.checked = true;
The checkbox has a single method, click().
This method simulates a click on the box. It also has a single
event, onClick, which occurs
whenever the checkbox is clicked. This happens whether the box
was turned on or off, so you'll need to check the checked
property.
Caution |
The click() method does not work properly in some versions of Netscape. You should avoid it when possible.
|
Radio buttons are similar to checkboxes, but an entire group of
them shares a single name and a single object. You can refer to
the following properties of the radio
object:
- name is the name common
to the radio buttons.
- length is the number
of radio buttons in the group.
To access individual buttons, you treat the radio object as an
array. The buttons are indexed, starting with 0.
Each individual button has the following properties:
- value is the value assigned
to the button. (This is used by the server.)
- defaultChecked indicates
the value of the chECKED
attribute and the default state of the button.
- checked is the current
state.
For example, you can check the first radio button in the radio1
group on the form1 form with
this statement:
document.form1.radio1[0].checked = true;
However, if you do this, be sure you set the other values to false
as needed. This is not done automatically. You can use the click
method to do both of these in one step.
Like a checkbox, radio buttons have a click()
method and an onClick event
handler. Each radio button can have a separate statement for this
event.
Note |
A bug in Netscape Navigator 2.0 causes radio buttons to be indexed backward; index 0 will actually be the last button on the page. This is fixed in version 3.0 and later, but watch out for strange behavior when users use an old version.
|
A selection list is similar to radio buttons, because the entire
group of options shares a name. In this case, the data for each
element is stored in the options
array, which indexes the different options starting with 0.
The object for selection lists is the select
object. The object itself has the following properties:
- name is the name of the
selection list.
- length is the number
of options in the list.
- options is the array
of options (explained later).
- selectedIndex returns
the index value of the currently selected item. You can use this
to check the value easily. In a multiple-selection list, this
indicates the first selected item.
The options array has a single
property of its own, length,
which indicates the number of selections. In addition, each item
in the options array has
the following properties:
- index is the index into
the array.
- defaultSelected indicates
the state of the SELECTED
attribute.
- selected is the current
state of the option. Setting this property to true
selects the option. You can select multiple options if the MULTIPLE
attribute is included in the <SELECT>
tag.
- name is the value of
the NAME attribute. This
is used by the server.
- text is the text that
is displayed in the option. In Netscape 3.0 or later, you can
change this value.
The select object has two
methods, blur() and focus().
These perform the same purpose as the corresponding methods for
text objects. The event handlers
are onBlur, onFocus,
and onChange, also similar
to other objects.
You can change selection lists dynamically-for example, choosing
a product in one list could control which options are available
in another list. You can also add and delete options from the
list. You will look at these capabilities in Chapter 11, "Real-Life
Examples II."
Note |
The onChange event doesn't work for select lists in some versions of Netscape . It does work properly in version 3.0 and later.
|
Hidden fields are stored in hidden
objects. This object has two properties, name
and value. These function
similarly to a text field. There are no methods or event handlers
for the hidden object-it can't be changed, so the user can't really
mess with a hidden field.
Buttons can be defined as SUBMIT buttons, RESET buttons, or generic
BUTTON buttons. All of these types have the same properties, methods,
and events.
Buttons support the name
property, used to identify the button, and the value
property, which defines the button's text. You cannot change either
of these values. Buttons support a single method, click(),
and an event handler, onClick.
The onClick action is performed
with any button. In the case of a generic button, nothing else
happens. In a SUBMIT or RESET button, you can prevent the submission
or resetting by returning a false value.
Note |
As with radio buttons and checkboxes, the click method may not work with some older versions of Netscape. Check your version before attempting to use it, and expect trouble from users of older versions.
|
A relatively new feature of Netscape enables you to define a file
upload field on a form. This enables the user to upload a
file to the server. You can define a file upload field with an
<INPUT> tag:
<INPUT TYPE="file" NAME="fname">
Because this field is mainly for interacting with the server,
JavaScript has little control over it. A FileUpload
object represents the field, and you can access two properties:
- name is the name of the
field, as defined in the <INPUT>
tag.
- value is the name of
the file (if any) the user is uploading.
You now have quite a bit of information about the many form-related
objects and how they can be used in JavaScript. Let's bring this
information into the real world by demonstrating how you can add
friendly, interactive features to the FSC order form created earlier
in this chapter.
At present, the order form isn't any more convenient than a paper
one-the user still has to calculate the total for each item and
the grand total manually. Let's use JavaScript to make those functions
automatic. You will do this with the onChange
event handler, so each time a quantity is changed, the associated
totals will be updated.
To start with, you will make each item's cost field update when
its quantity field is changed. To do this, you'll use the onChange
event handler for each of the quantity text fields. For example,
here's what the first one will look like:
Qty: <INPUT TYPE="TEXT" NAME="qty1" VALUE="0" SIZE=4
onChange = "UpdateCost(1, 40.00);">
This calls a function called UpdateCost(),
which takes two parameters: the item number to update (1
through 4) and the associated
unit cost. You then need to define the UpdateCost()
function in the HTML header. Here's the function:
// function to update cost when quantity is changed
function UpdateCost(number, unitcost) {
costname = "cost" + number;
qtyname = "qty" + number;
var q = document.order[qtyname].value;
document.order[costname].value = q * unitcost;
Total();
}
This function stores the item number and unit cost in the number
and unitcost variables. It
then constructs names for the cost and quantity elements; because
they have been named consistently (such as qty1
through qty4), this is simple.
A temporary variable, q,
is used to hold the quantity field's current value. Notice that
you have to use brackets around qtyname,
because you want to use the value of this variable, not its actual
name. The quantity in q is
then multiplied by the unit cost and stored in the appropriate
cost text field.
Finally, you include a function call for the Total()
function, which will calculate the total cost each time a field
is changed. Here is the definition for this function:
// function to calculate the total cost field
function Total() {
var tot = 0;
tot += (40.00 * document.order.qty1.value);
tot += (69.95 * document.order.qty2.value);
tot += (99.95 * document.order.qty3.value);
tot += (4.95 * document.order.qty4.value);
document.order.totalcost.value = tot;
}
This function simply uses a temporary variable called tot
to add up each of the costs, which it gets by multiplying the
appropriate prices by the quantities. It then stores the value
of tot in the total cost
text field.
Listing 6.2 shows the revised HTML order form including the new
functions. You now have an order form that updates automatically-each
time you enter or change a quantity, the cost for that item and
the total cost are updated. Figure 6.4 shows the order form after
several quantities have been entered.
Figure 6.4 : The order form with automatically updated
numeric totals.
Listing 6.2. The revised HTML order form, including automatic
update functions.
<HTML>
<HEAD><TITLE>Order Form</TITLE>
<SCRIPT>
// function to calculate the total cost field
function Total() {
var tot = 0;
tot += (40.00 * document.order.qty1.value);
tot += (69.95 * document.order.qty2.value);
tot += (99.95 * document.order.qty3.value);
tot += (4.95 * document.order.qty4.value);
document.order.totalcost.value = tot;
}
// function to update cost when quantity is changed
function UpdateCost(number, unitcost) {
costname = "cost" + number;
qtyname = "qty" + number;
var q = document.order[qtyname].value;
document.order[costname].value = q * unitcost;
Total();
}
</SCRIPT>
</HEAD>
<BODY>
<H1>Order Form</H1>
<FORM NAME="order">
<B>Name:</B> <INPUT TYPE="text" NAME="name1" SIZE=20>
<B>Phone: </B><INPUT TYPE="text" NAME="phone" SIZE=15>
<B>E-mail address:</B><INPUT TYPE="text" NAME="email" SIZE=20><BR>
<B>Billing and Shipping Addresses:</B><BR>
<TEXTAREA NAME="billto" COLS=40 ROWS=4>
Enter your billing address here.
</TEXTAREA>
<TEXTAREA NAME="shipto" COLS=40 ROWS=4>
Enter your shipping address here.
</TEXTAREA>
<B>Products to Order:</B><BR>
Qty: <INPUT TYPE="TEXT" NAME="qty1" VALUE="0" SIZE=4
onChange = "UpdateCost(1, 40.00);">
Cost: <INPUT TYPE="TEXT" NAME="cost1" SIZE=6>
($40.00 ea) Fictional Spreadsheet 7.0 <BR>
Qty: <INPUT TYPE="TEXT" NAME="qty2" VALUE="0" SIZE=4
onChange = "UpdateCost(2, 69.95);">
Cost: <INPUT TYPE="TEXT" NAME="cost2" SIZE=6>
($69.95 ea) Fictional Word Processor 6.0<BR>
Qty: <INPUT TYPE="TEXT" NAME="qty3" VALUE="0" SIZE=4
onChange = "UpdateCost(3, 99.95);">
Cost: <INPUT TYPE="TEXT" NAME="cost3" SIZE=6>
($99.95 ea) Fictional Database 7.0 <BR>
Qty: <INPUT TYPE="TEXT" NAME="qty4" VALUE="0" SIZE=4
onChange = "UpdateCost(4, 4.95);">
Cost: <INPUT TYPE="TEXT" NAME="cost4" SIZE=6>
($4.95 ea) Instruction guidelet for the above <HR>
<B>Total Cost:</B>
<INPUT TYPE="TEXT" NAME="totalcost" SIZE=8><HR>
<B>Method of Payment</B>:
<SELECT NAME="payby">
<OPTION VALUE="check" SELECTED>Check or Money Order
<OPTION VALUE="cash">Cash or Cashier's Check
<OPTION VALUE="credit">Credit Card (specify number)
</SELECT><BR>
<B>Credit Card or Check Number:</B>:
<INPUT TYPE="TEXT" NAME="creditno" SIZE="20"><BR>
<INPUT TYPE="SUBMIT" NAME="submit" VALUE="Send Your Order">
<INPUT TYPE="RESET" VALUE="Start Over">
</FORM>
</BODY>
</HTML>
Because the order form includes spaces for separate billing and
shipping addresses, it's a good idea to give the user an option
to use the same address for both. Using JavaScript, you can add
such an option easily-and it makes for a neat bit of automation.
To accomplish this, you'll add a checkbox above the addresses
and label it:
<INPUT TYPE="chECKBOX" NAME="same" onClick="CopyAddress();">
Ship to Billing Address
You'll use the onClick event
handler for the checkbox to handle the copying. Here is the CopyAddress
function for copying the address:
// function to copy billing address to shipping address
function CopyAddress() {
if (document.order.same.checked) {
document.order.shipto.value = document.order.billto.value;
}
}
This function checks the checked
property of the checkbox, and if it's currently checked, it copies
the billing address to the shipping address.
This works when the checkbox is checked, but what about when the
user changes the billing address after checking the box? You will
use the onChange event handler
to do the copy again whenever the billing address changes:
<TEXTAREA NAME="billto" COLS=40 ROWS=4 onChange="CopyAddress();">
Enter your billing address here.
</TEXTAREA>
There's one possibility left: after checking the box, the user
might mistakenly change the shipping address. Because you want
the addresses to be the same, you use the same event handler on
the shipping address. Therefore, when the user changes
the shipping address with the box checked, it will immediately
be changed back to the billing address.
Listing 6.3 is the latest version of the HTML form, including
the automatic address-copying function you just added. Figure
6.5 shows how the new form looks in Netscape.
Figure 6.5 : The order form with address-copying feature.
Listing 6.3. The revised HTML order form with the address-copying
features.
<HTML>
<HEAD><TITLE>Order Form</TITLE>
<SCRIPT>
// function to calculate the total cost field
function Total() {
var tot = 0;
tot += (40.00 * document.order.qty1.value);
tot += (69.95 * document.order.qty2.value);
tot += (99.95 * document.order.qty3.value);
tot += (4.95 * document.order.qty4.value);
document.order.totalcost.value = tot;
}
// function to update cost when quantity is changed
function UpdateCost(number, unitcost) {
costname = "cost" + number;
qtyname = "qty" + number;
var q = document.order[qtyname].value;
document.order[costname].value = q * unitcost;
Total();
}
// function to copy billing address to shipping address
function CopyAddress() {
if (document.order.same.checked) {
document.order.shipto.value = document.order.billto.value;
}
}
</SCRIPT>
</HEAD>
<BODY>
<H1>Order Form</H1>
<FORM NAME="order">
<B>Name:</B> <INPUT TYPE="text" NAME="name1" SIZE=20>
<B>Phone: </B><INPUT TYPE="text" NAME="phone" SIZE=15>
<B>E-mail address:</B><INPUT TYPE="text" NAME="email" SIZE=20><BR>
<B>Billing and Shipping Addresses:</B>
<INPUT TYPE="chECKBOX" NAME="same" onClick="CopyAddress();">
Ship to Billing Address
<BR>
<TEXTAREA NAME="billto" COLS=40 ROWS=4 onChange="CopyAddress();">
Enter your billing address here.
</TEXTAREA>
<TEXTAREA NAME="shipto" COLS=40 ROWS=4 onChange="CopyAddress();">
Enter your shipping address here.
</TEXTAREA>
<B>Products to Order:</B><BR>
Qty: <INPUT TYPE="TEXT" NAME="qty1" VALUE="0" SIZE=4
onChange = "UpdateCost(1, 40.00);">
Cost: <INPUT TYPE="TEXT" NAME="cost1" SIZE=6>
($40.00 ea) Fictional Spreadsheet 7.0 <BR>
Qty: <INPUT TYPE="TEXT" NAME="qty2" VALUE="0" SIZE=4
onChange = "UpdateCost(2, 69.95);">
Cost: <INPUT TYPE="TEXT" NAME="cost2" SIZE=6>
($69.95 ea) Fictional Word Processor 6.0<BR>
Qty: <INPUT TYPE="TEXT" NAME="qty3" VALUE="0" SIZE=4
onChange = "UpdateCost(3, 99.95);">
Cost: <INPUT TYPE="TEXT" NAME="cost3" SIZE=6>
($99.95 ea) Fictional Database 7.0 <BR>
Qty: <INPUT TYPE="TEXT" NAME="qty4" VALUE="0" SIZE=4
onChange = "UpdateCost(4, 4.95);">
Cost: <INPUT TYPE="TEXT" NAME="cost4" SIZE=6>
($4.95 ea) Instruction guidelet for the above <HR>
<B>Total Cost:</B>
<INPUT TYPE="TEXT" NAME="totalcost" SIZE=8><HR>
<B>Method of Payment</B>:
<SELECT NAME="payby">
<OPTION VALUE="check" SELECTED>Check or Money Order
<OPTION VALUE="cash">Cash or Cashier's Check
<OPTION VALUE="credit">Credit Card (specify number)
</SELECT><BR>
<B>Credit Card or Check Number:</B>:
<INPUT TYPE="TEXT" NAME="creditno" SIZE="20"><BR>
<INPUT TYPE="SUBMIT" NAME="submit" VALUE="Send Your Order">
<INPUT TYPE="RESET" VALUE="Start Over">
</FORM>
</BODY>
</HTML>
The final feature you can add to a form with JavaScript is perhaps
the most important: validation. This means checking each field
to ensure that it contains a proper value and advising the user
if it is incorrect.
Obviously, validating can only do so much. For example, you can't
tell whether a phone number is valid or whether a name is an alias.
You can tell whether it exists, though, and whether it's in the
right format.
Validation saves you some trouble when you receive a response.
More importantly, it saves you the trouble of performing the validation
in the CGI script. This enables you to use a generic CGI script,
and enables the user to receive immediate feedback without waiting
on the server.
You could use the onChange
event handler on each of the fields to validate it. For example,
as soon as users enter their names and move to the next field,
you could alert them if the names are invalid.
This method is worth considering in some cases, but for most forms
it's best to validate all the fields at once, using the form's
onSubmit event handler. This
enables users to correct any fields necessary, then press submit
when they're really ready.
For the FSC order form, you will use a single onSubmit
event handler to perform the validation for all the fields.
Tip |
If you choose to validate fields as they change, you might find it useful to use the this keyword. Within an event handler, this represents the object that triggered the event. This technique enables you to use a single validation routine
for several fields.
|
When choosing how to handle validation for a form, the first step
is to decide which fields you need to validate and what to check
for. For some items, such as a name, the most you can do is see
whether anything is entered.
For other items you can be more specific; for example, if your
form asked for the user's age, you can check for numbers over
100 or so. (I would suggest a lower limit, but the Internet audience
is getting younger every day.)
For the FSC order form, let's use the following validation criteria:
- The name must be at least 6 characters, and the billing address
and shipping address must be at least 30 characters. The phone
number must be at least 10 characters. (You want them to include
the area code.)
- The e-mail address must be at least 5 characters and include
the @ symbol.
- Because the cost fields are calculated automatically, you
won't bother validating them. However, you'll check the total
cost; if it's 0 or blank,
they haven't ordered anything.
- If the payment method is anything but cash, the credit card
number/check number field must be at least 2 characters.
Obviously, you could make some of these more specific, but they'll
do to illustrate the concept. You'll need to choose the appropriate
values for each form with which you work.
Based on the decisions made previously, you now need to create
a function to handle each of the fields. In some cases, you can
use the same function for multiple fields. Let's start with the
simplest function: checking for the proper length. This function
will work with the name, billing address, and phone number fields.
function ValidLength(item, len) {
return (item.length >= len);
}
This function expects the name of an item and the required length.
It simply checks whether the item is greater than or equal to
that length, and it returns true or false appropriately.
Next, let's create a function for the e-mail address. This will
simply call the ValidLength
function to check the length, then use the indexOf
string method to check for the @
sign:
//function to validate an email address
function ValidEmail(item) {
if (!ValidLength(item, 5)) return false;
if (item.indexOf ('@', 0) == -1) return false;
return true;
}
Finally, let's create a main validation routine. This routine
validates all the fields one at a time, then returns true or false:
function Validate() {
errfound = false;
if (!ValidLength(document.order.name1.value,6))
error(document.order.name1,"Invalid Name");
if (!ValidLength(document.order.phone.value,10))
error(document.order.phone,"Invalid Phone");
if (!ValidLength(document.order.billto.value,30))
error(document.order.billto,"Invalid Billing Address");
if (!ValidLength(document.order.shipto.value,30))
error(document.order.shipto,"Invalid Shipping Address");
if (!ValidEmail(document.order.email.value))
error(document.order.email, "Invalid Email Address");
if (document.order.totalcost.value == "")
error(document.order.qty1, "Please Order at least one item.");
if (document.order.payby.selectedIndex != 1) {
if (!ValidLength(document.order.creditno.value,2))
error(document.order.creditno,"Invalid Credit/Check number");
}
return !errfound; /* true if there are no errors */
}
As you can see, this function includes tests for the length-related
functions and the e-mail address; in addition, I have added checks
for the credit card number and the total cost. If any of these
checks fails, an error routine is called:
function error(elem, text) {
// abort if we already found an error
if (errfound) return;
window.alert(text);
elem.select();
elem.focus();
errfound = true;
}
This function displays a dialog explaining the error, then sets
the focus to the element with the error; this positions the cursor
in that field so the user can easily change it. In addition, the
select method is used to
select the item's text.
Note |
Because the user doesn't normally enter data in the total cost field, the validate routine points the cursor to the first quantity field, so the user can add an item to the order.
|
One more thing: the error
function sets a variable, errfound,
to indicate that an error has happened. It returns immediately
if an error was already found; this prevents multiple dialogs
from showing if more than one field is invalid.
Finally, you can link the validation routine to the form itself.
You will add an onSubmit
event handler to the FORM
declaration:
<FORM NAME="order" onSubmit="return Validate();">
This calls the Validate function
and uses its return value as the return value of the event. This
means that if Validate returns
false-in other words, if something is invalid-the data will not
be submitted.
This basically completes the order form. Listing 6.4 is the complete
HTML listing, including all the validation scripting. The complete
form is shown in Figure 6.6, including a dialog indicating that
the e-mail address is invalid.
Figure 6.6 : The complete HTML order form, including
validation for all fields.
Listing 6.4. The revised HTML order form with validation.
<HTML>
<HEAD><TITLE>Order Form</TITLE>
<SCRIPT>
// function to calculate the total cost field
function Total() {
var tot = 0;
tot += (40.00 * document.order.qty1.value);
tot += (69.95 * document.order.qty2.value);
tot += (99.95 * document.order.qty3.value);
tot += (4.95 * document.order.qty4.value);
document.order.totalcost.value = tot;
}
// function to update cost when quantity is changed
function UpdateCost(number, unitcost) {
costname = "cost" + number;
qtyname = "qty" + number;
var q = document.order[qtyname].value;
document.order[costname].value = q * unitcost;
Total();
}
// function to copy billing address to shipping address
function CopyAddress() {
if (document.order.same.checked) {
document.order.shipto.value = document.order.billto.value;
}
}
//global variable for error flag
var errfound = false;
//function to validate by length
function ValidLength(item, len) {
return (item.length >= len);
}
//function to validate an email address
function ValidEmail(item) {
if (!ValidLength(item, 5)) return false;
if (item.indexOf ('@', 0) == -1) return false;
return true;
}
// display an error alert
function error(elem, text) {
// abort if we already found an error
if (errfound) return;
window.alert(text);
elem.select();
elem.focus();
errfound = true;
}
// main validation function
function Validate() {
errfound = false;
if (!ValidLength(document.order.name1.value,6))
error(document.order.name1,"Invalid Name");
if (!ValidLength(document.order.phone.value,10))
error(document.order.phone,"Invalid Phone");
if (!ValidLength(document.order.billto.value,30))
error(document.order.billto,"Invalid Billing Address");
if (!ValidLength(document.order.shipto.value,30))
error(document.order.shipto,"Invalid Shipping Address");
if (!ValidEmail(document.order.email.value))
error(document.order.email, "Invalid Email Address");
if (document.order.totalcost.value == "")
error(document.order.qty1, "Please Order at least one item.");
if (document.order.payby.selectedIndex != 1) {
if (!ValidLength(document.order.creditno.value,2))
error(document.order.creditno,"Invalid Credit/Check number");
}
return !errfound; /* true if there are no errors */
}
</SCRIPT>
</HEAD>
<BODY>
<H1>Order Form</H1>
<FORM NAME="order" onSubmit="return Validate();">
<B>Name:</B> <INPUT TYPE="text" NAME="name1" SIZE=20>
<B>Phone: </B><INPUT TYPE="text" NAME="phone" SIZE=15>
<B>E-mail address:</B><INPUT TYPE="text" NAME="email" SIZE=20><BR>
<B>Billing and Shipping Addresses:</B>
<INPUT TYPE="chECKBOX" NAME="same" onClick="CopyAddress();">
Ship to Billing Address
<BR>
<TEXTAREA NAME="billto" COLS=40 ROWS=4 onChange="CopyAddress();">
Enter your billing address here.
</TEXTAREA>
<TEXTAREA NAME="shipto" COLS=40 ROWS=4 onChange="CopyAddress();">
Enter your shipping address here.
</TEXTAREA>
<B>Products to Order:</B><BR>
Qty: <INPUT TYPE="TEXT" NAME="qty1" VALUE="0" SIZE=4
onChange = "UpdateCost(1, 40.00);">
Cost: <INPUT TYPE="TEXT" NAME="cost1" SIZE=6>
($40.00 ea) Fictional Spreadsheet 7.0 <BR>
Qty: <INPUT TYPE="TEXT" NAME="qty2" VALUE="0" SIZE=4
onChange = "UpdateCost(2, 69.95);">
Cost: <INPUT TYPE="TEXT" NAME="cost2" SIZE=6>
($69.95 ea) Fictional Word Processor 6.0<BR>
Qty: <INPUT TYPE="TEXT" NAME="qty3" VALUE="0" SIZE=4
onChange = "UpdateCost(3, 99.95);">
Cost: <INPUT TYPE="TEXT" NAME="cost3" SIZE=6>
($99.95 ea) Fictional Database 7.0 <BR>
Qty: <INPUT TYPE="TEXT" NAME="qty4" VALUE="0" SIZE=4
onChange = "UpdateCost(4, 4.95);">
Cost: <INPUT TYPE="TEXT" NAME="cost4" SIZE=6>
($4.95 ea) Instruction guidelet for the above <HR>
<B>Total Cost:</B>
<INPUT TYPE="TEXT" NAME="totalcost" SIZE=8><HR>
<B>Method of Payment</B>:
<SELECT NAME="payby">
<OPTION VALUE="check" SELECTED>Check or Money Order
<OPTION VALUE="cash">Cash or Cashier's Check
<OPTION VALUE="credit">Credit Card (specify number)
</SELECT><BR>
<B>Credit Card or Check Number:</B>:
<INPUT TYPE="TEXT" NAME="creditno" SIZE="20"><BR>
<INPUT TYPE="SUBMIT" NAME="submit" VALUE="Send Your Order">
<INPUT TYPE="RESET" VALUE="Start Over">
</FORM>
</BODY>
</HTML>
Tip |
At this point, submitting the form won't do anything; however, you can still test the submission. Submitting will reload the current page and add the various data to the URL.
|
In this chapter, you built a fully functional ordering system
for an imaginary company, which could easily be modified for use
by a real company. In the process, you learned the following:
- How to use HTML forms and their many elements in a Web page
- How to use JavaScript to add validation to the form
- How to use JavaScript to add automation to a form
- About the <FORM>
object and form elements, and how to manipulate and read each
of their values in JavaScript
You should now know how to use JavaScript with forms. To move
on, turn to one of the following chapters:
- To learn about the object hierarchy that underlies forms,
see Chapter 5 "Accessing Window Elements as Objects."
- To see another example of form validation, turn to Chapter
7, "Real-Life Examples I."
- To learn to add functionality to a Web page, such as navigation
bars and the status line, see Chapter 8 "Improving a Web
Page with JavaScript."
- To learn about advanced browser features such as frames, see
Chapter 9 "Using Frames, Cookies, and Other Advanced Features."
- To learn more about CGI and interactive forms, see Chapter
17, "Combining JavaScript, CGI and SSI."
Q: | Is there any way to force a form to be submitted automatically, without the user pressing a button?
|
A: | Yes. You can do this with the form.submit() method. However, this is bad manners; it's usually best to let the user know what's going on. Also note that due to security
concerns, you can't do this with a form that uses the mailto action.
|
Q: | I am having problems trying to force a checkbox to be selected using the click method. Is there a way to solve this?
|
A: | Unfortunately, at least for many versions of Netscape, the only solution is not to use the click method. Fortunately, it's easy to do most things without it. For a checkbox,
you can manipulate the checked property; for a button, you can call the same function as its onClick event handler.
|
Q: | If I use JavaScript to add validation and other features to my form, can users with non-JavaScript browsers still use the form?
|
A: | Yes, if you're careful. Be sure to use a SUBMIT button rather than the submit action. Also, because the CGI script may receive nonvalidated data, be sure to include
validation in the CGI script. Non-JavaScript users will be able to use the form but won't receive instant feedback about their errors.
|
Q: | Can I add new form elements "on the fly," or change them-for example, change a text box into a password field?
|
A: | No. The form elements are set by the HTML code. There are ways to work around this, such as updating the form in a separate frame.
|
Q: | Is there any way to create a large number of text fields without dealing with different names for all of them?
|
A: | Yes. If you use the same name for several elements in the form, their objects will form an array. For example, if you defined 20 text fields with the name member, you could
refer to them as member[0] through member[19]. Chapter 15, "Real-Life Examples III," uses this technique for score values in a game.
|
Q: | When validating an e-mail address, is there any way to be sure the address is valid, or that it is the user's address?
|
A: | No. This is a classic question about CGI; neither JavaScript nor CGI has a good solution. The only way to be sure an e-mail address is valid is to send information, such as a
password, to the address; even then, you can't be sure users are entering their own addresses.
|
Q: | Why doesn't JavaScript recognize my form elements when I use a table to lay them out?
|
A: | JavaScript does not deal well with forms within tables when <TABLE> tags are nested. For now, the only solution is to avoid using nested tables.
|
Q: | Is there a way to place the cursor on a particular field when the form is loaded?
|
A: | Yes. You can use the field's focus() method to send the cursor there. The best way to do this is to use an onLoad event handler and add a slight delay with the
setTimeout() method to allow the page to finish loading.
|
|