Notice: This material is excerpted from Special
Edition Using JavaScript, ISBN: 0-7897-0789-6. The electronic version
of this material has not been through the final proof
reading stage that
the book goes through before being published in printed form. Some errors
may exist here that are corrected before the book is published. This material
is provided "as is" without any warranty of any kind.
Although HTML pages can be difficult to develop, they are usually
very simple to use. The number of things you can do with an
HTML
page is quite limited. For the most part you simply look at it-read
its text, admire its graphics, and, perhaps, listen to the sounds
it can play. For many, the
Web experience consists of visiting
a series of pages without interacting with them. The only interaction
occurs when the user selects a link or clicks an imagemap.
HTML forms have gradually changed that model to increase the level
of interaction. A form can have a variety of ways of accepting
input, include text fields, buttons, checkboxes, and multiple
choice selections. In this way,
HTML forms are a lot like paper
forms. The user fills in the form, perhaps to purchase some item,
and then submits the form. This submission process also mimics
real life. It is difficult to tell if the form has been properly
filled in, and the time taken for processing the form is often
quite lengthy. In the case of HTML, this processing delay occurs
because the contents of the form must be sent across the network
to some URL, processed there, and then returned to the user. Even
the slightest error causes the form to be rejected, so that the
form entry must be repeated.
One of the primary goals of JavaScript is to localize most of
this process and perform the form validation within the user's
browser. It won't be possible to actually submit an order locally,
but it will be possible to make sure that the form is properly
filled out locally, and thereby avoid forcing the user to redo
the form. JavaScript realizes this goal through event handlers.
Event handlers are JavaScript statements (usually functions) that
are called whenever something happens. JavaScript functions can
be called when a form is submitted, or they can be called whenever
the user does anything to the form. If your form requires that
a certain field correspond to a number between 2 and 10, for example,
you can write a JavaScript function that will validate that field
when the user changes it, and complain if the value is out of
range.
This chapter describes event handling in JavaScript. We discuss all the events that can be handled, as well as the contexts in which these events may arise. In addition, you learn how JavaScript can be included within Web pages, and how JavaScript functions are connected with different components of that page. You learn to do the following:
To understand JavaScript's event handling model, you must first
think about the set of things that can actually happen on a Web
page. Although there are many different things you can do with
the browser, most of these have nothing to do with
Web navigation.
When you save a page as text, print a page, or edit your hotlist,
you are not actually navigating the Web. In these cases, you are
using some of the
graphical capabilities of the browser, which
are independent of the Web.
To understand which browser actions correspond to JavaScript events
and which do not, it is important to distinguish those actions
that actually cause (or might cause) some change in the
Web page
being displayed. From the user's standpoint the number of such
actions is actually quite limited. In fact, there are really only
two types of top level actions: the user can navigate, or the
user can interact with an element of an
HTML form.
Navigation
means to change from one
Web page to another, or perhaps to open
a completely new page in a new window. Interaction with the contents
of an
HTML form means changing one or more of the elements in
such a form that can be changed, such as editable text fields.
In the navigation category, you can distinguish the following
different actions:
In most of these cases the current page will be unloaded,
which means it will no longer be visible in any browser window.
In several of these cases a new page will be loaded, which
means its contents will be displayed in a browser window, perhaps
a new one created specifically to display this particular page.
Anyone who has used the World Wide Web realizes that selecting
a
hypertext link may not successfully take you to another. The
machine to which that link points may be down, or simply inaccessible.
The link may even be dead, meaning that it does not point to a
valid destination. Selecting a dead link often unloads the current
page, but doesn't load a new page. Most browsers display a blank
page or post an error message. You may or may not be left on the
current page, depending on the type of error and the browser being
used. A sample error alert from Netscape is shown in figure 3.1.
FIG. 3.1 Attempting to access a non-existent URL generates results in an error message on some browsers.
These events, loading and unloading a page, are the two document
level events that can be handled by JavaScript. This means that
it is possible to write JavaScript code, contained within the
HTML definition of a page, that will be executed whenever that
page is loaded. You can also have code that is executed whenever
that page is unloaded. The dead link example illustrates the important
fact that loading and unloading are two separate, unrelated events.
When you attempt to activate a dead link, the current page is
unloaded, but nothing is loaded in its place. In order to return
to the last valid Web page you must use one of your browser's
navigation controls. For example, if you select Back in Netscape
the last page you visited is reloaded.
There are two additional events that are vaguely related to navigation.
These events are the following:
When you move the mouse over a
hypertext link, a
mouseover
event is generated. This event is not associated with clicking
the link, it is associated with being poised to click it.
This event can be used to give the user feedback, such as changing
the color of the link or flashing it. The final event is the
statechange
event. This event has been proposed by
Microsoft as part of their
planned implementation of an open
scripting architecture that
will include
Visual Basic Script as well as JavaScript. The purpose
of this event is to provide staged notifications when a time-consuming
operation is taking place. For example, if a movie player plug-in
is being loaded, the
statechange event might be issued
to indicate the plug-in is ready to accept some user interaction,
but cannot yet display its movie.
See Chapter 14, "VB Script and OLE Controls," for more information on the Visual Basic Script language, and its plug-in technology, OLE Controls.
We have now discussed the events that arise if you are using the
browser to navigate the Web. Of course, you can also interact
with your browser through the elements of an HTML form. Every
form element that permits input is associated with one or more
JavaScript events. We can broadly characterize the possible components
of an HTML form as follows (chapter 6, "Interactive HTML
Objects," has a "Review of HTML Forms" section):
Buttons come in five varieties, as follows:
Simple buttons are defined using the HTML <INPUT TYPE="button">.
Checkboxes define options, which are either off (not checked)
or on (checked). These are created using an <INPUT TYPE="checkbox">
directive. Radio buttons use the <
INPUT TYPE="radio">
directive, and permit the user to select exactly one of a set
of choices. Submit buttons and reset buttons are very special.
Submit buttons, created by <
INPUT TYPE="submit">
,
are used to end input operations on a form. When the submit button
is pressed the contents of the form are packaged and sent to the
URL target specified in the
ACTION attribute of the <FORM>
definition. Reset buttons bring the form back to its initial state,
wiping out any input the user has performed; they are specified
as <
INPUT TYPE="reset">
. Figure 3.2 shows
a simple
HTML form with all five button types; it was generated
by the HTML file allbut.htm.
FIG. 3.2 All five types of HTML buttons have corresponding JavaScript events.
Hidden fields onHTML forms do not generate
JavaScript events.
The one thing the five types of buttons have in common is that
you click the button to achieve its effect. Because this is an
extremely common action JavaScript event model defines click
as one of its
HTML form events. This event is generated by each
of the five button types. In addition, when a form is actually
submitted, a submit event is generated. The submit
event is really owned by the form being submitted, and not the
submit button that causes it.
There are three types of text items possible within an HTML form, as follows:
Single line text fields are created with an <INPUT TYPE="text">
directive. Any text you type in a text field is displayed as you
type it. This behavior is known as echoing the input. Single
line text fields that are created using <INPUT TYPE="password">
do not echo their input. Multi-line text fields are created with
the TEXTAREA tag, and are usually called
textareas. An
HTML form showing all three types of text elements is shown in
figure 3.3, created from the file
alltxt.htm. Interacting with
text is more complex than interacting with a button. There are
more things you can do with text. You can click in the text field,
enter text, edit text, select text, and decide you are finished
with the text and move on.
FIG. 3.3 HTML text elements generate several different JavaScript events.
What are the events JavaScript generates in response to these
various actions? JavaScript uses a text manipulation model which
will be familiar to anyone who has ever used a windowing system.
It defines four events that are associated with text fields and
textareas, but not passwords fields-change, select,
focus, and blur. The first two should be self-explanatory.
The change event is generated whenever any text is changed,
and the select event is generated whenever text is selected.
Selecting text is more than simply clicking in the editable text
field or textarea. It means actually highlighting a portion of
the text with the mouse.
Password fields do not generateJavaScript events. This was a conscious design decision to prevent malicious script code from diverting password text.
focus and blur are a little more involved. A
text field or textarea is said to have focus when it is currently
accepting input typed at the
keyboard. Clicking anywhere inside
a text item is certain to give it focus, and simply moving the
mouse over the text field may do so as well. blur is
the opposite of focus. Blur occurs when the text item
no longer has focus. This may happen because some other item now
has the focus, or because the focus has simply been lost. You
will notice that if you position the mouse over a graphic (other
than an imagemap), you can type until your fingers are sore, but
nothing happens. This is a case where nothing has focus.
Selection lists are defined by the SELECT tag; their
options are enumerated using the
OPTION tag. They operate
almost the same as text items; they are capable of generating
focus, blur, and change events. Paradoxically,
selection lists do not generate select events. You might
well wonder why four events types are needed for text and three
for lists. This is clarified later in this chapter. Figure 3.4
summarizes the events understood by JavaScript and the
HTML elements
that generate them.
The topic of text events is covered in much greater detail in Chapter 6, "Interactive HTML Objects," particularly in the section on "Manipulating Text Fields.".
FIG. 3.4 JavaScript events model different types of user interaction with a Web page.
Anything not mentioned in the previous two sections should be
considered an action, not a JavaScript event. Scrolling a window,
reading newsgroups, or answering mail are certainly actions, but
they are not events. Using the Back, Forward, or Home buttons
on
Netscape's toolbar are not really
JavaScript events, but they
ultimately result in JavaScript events being delivered to the
current page, since they unload the current document. Creating
a bookmark or
hotlist entry is not even remotely related to
JavaScript
events, since that does not effect the current page at all. How
does one distinguish actions that might possibly be events from
those which are not? The rule is that if an action affects or
changes the current page, it is associated with one or more JavaScript
events.
It might be argued that scrolling or resizing a window affects
the current page, and should therefore result in some kind of
event. Those of you who have programmed any kind of windowing
system know these are visibility, or window damage,
events. JavaScript takes a more literal definition of a page.
No matter how much or how little of a Web page is visible, it
is still the same page. Even if you only read the cartoons in
The New Yorker, the articles are still there, unchanged.
So far we have talked about JavaScript as a language, and we have
talked a bit about HTML, but we have not talked about how JavaScript
is used in HTML. Event handlers are the glue that link HTML elements
with JavaScript code, but how is it done? This section addresses
this question. The answer has two parts: how JavaScript is included
or referenced in a Web page, and how event handlers are attached
to
HTML items.
In the most general sense, every Web page is constructed from
HTML statements that divide the page into two parts: the <HEAD>
and the <BODY>. The HTML directives within the
context of the <HEAD> give information about the
page, while those in the <BODY> make up the page
itself. In most simple
HTML documents the <HEAD>
usually contains only the <TITLE>. It can also
contain a
BASE tag which specifies a pathname that should
be used to resolve relative HREFs within the document, and one
or more
LINK tags, which indicate the relationship of
this document to one or more other documents, such as the browser's
home page.
The HEAD section of an HTML document also contains the
JavaScript code for your event handlers. While it is not absolutely
necessary for all JavaScript code to go with the <HEAD>...</HEAD>
delimiters, it is an excellent idea because it ensures that all
JavaScript code has been defined before any of the <BODY>
of the document is seen. In particular, if the document has a
handler for the load event, and that event was triggered
before that code had been read, an error would result because
the event handler function would be undefined.
JavaScript code is introduced with the
SCRIPT tag. Everything
between this tag and the closing /
SCRIPT tag is assumed
to be some kind of client-side script code, such as JavaScript.
The syntax for the
SCRIPT tag is
<SCRIPT LANGUAGE="LangName" [SRC="URL"]>
The element LangName gives the language that is used
in the subsequent script code; this should be JavaScript. Strictly
speaking, the LANGUAGE attribute is not required; at
present, Netscape Navigator is the only browser that is widely
available and understands any
scripting language. Of course, the
language it understands is JavaScript. This will certainly change
very quickly, so it is a good idea to always include the
LANGUAGE
attribute.
If the SRC attribute is specified then it should reference
a URL containing code in the script language. For JavaScript,
this should be a valid URL for a file containing the JavaScript
code. The filename should have the suffix .js. If the
SRC attribute is given then the <SCRIPT>
can be immediately terminated by a </SCRIPT> directive.
A <SCRIPT> block that loads JavaScript code from
a filename click.
js in a
directory jscode relative
to the document base would look like this:
<SCRIPT LANGUAGE="JavaScript" SRC="jscode/click.js"> </SCRIPT>
Netscape Navigator 2.0 does not yet support the
SRC attribute. This feature has been promised for version 2.1.
If the SRC attribute is not given then it is expected
that all the code between <SCRIPT> and </SCRIPT>
is the script source itself. In the glorious future, when the
overwhelming majority of browsers understand the
SCRIPT
tag, or at least benignly ignore it, the JavaScript source may
be given literally. Until then it is recommended that source included
between <SCRIPT> and </SCRIPT> be
enclosed within the HTML comment delimiters <!-- and
-->. A simple example showing a single
JavaScript
function is shown in listing 3.1.
Use the C-style comments // and /* */ inside JavaScript code. Never useHTML comments inside JavaScript.
Listing 3.1 A JavaScript<SCRIPT> with a Single Function <SCRIPT LANGUAGE="JavaScript"> <!-- function dontclickme() { // an ominous button click handler alert("I told you not to click me"); return( false ); } <!-- end script --> </SCRIPT>
The function in listing 3.1 does not do much; it merely uses the
alert() function to pop up a warning dialog box with
its argument as the message. Presumably this function is the click
event handler for a button you don't want the user to press. The
important thing to notice about this simple example is the paradoxical,
but important, use of HTML comments. The entire script body is
enclosed with a comment, and the comment close -->
is also paired with a second, seemingly redundant, comment start
<!-- on the last line. At present, you should structure
your script according to the following rules:
You should use this magic incantation not because it makes sense,
but because it works. Note that JavaScript code referenced through
a
SRC URL should also follow these rules, as if it had literally
been included in the <SCRIPT> block. Note also
that you may have both a JavaScript SRC URL, and literal JavaScript
between <SCRIPT> and </SCRIPT>.
In this case, the URL referenced by the
SRC attribute
is read and processed before the literal JavaScript.
HTML comments are one of the least conforming areas of
HTML. Most browsers deviate a little from the
HTML standards, and some deviate a lot. The preceding comment rules may change in the future, and may be implemented differently on different browsers.
There are two important aspects to JavaScript code defined by
or within a
SCRIPT block. The first important principle
is that this
JavaScript code is not executed-it is merely read
and checked for syntax errors. When the browser sees the code
shown in listing 3.1, it does not execute the dontclickme()
function, it merely recognizes that this function is a JavaScript
function, and saves the definition of that function for later
use. This is precisely the opposite behavior of normal HTML. When
you say <HR> in an HTML document, you get a horizontal
rule. You don't get it immediately, but you do get it when the
browser has finished laying out the page (assuming that there
are no HTML errors, of course).
This is the way that most interpreted languages work, however. If you create a Sub in BASIC, a defun in lisp, or a proc in Tcl, it is not executed when it is read. Instead, the interpreter parses it, which means that it scans through the function looking for obvious syntax errors, such as unbalanced parentheses, and records the function's definition for later use. The function is only used when it is called. In JavaScript, functions can only be called by events.
Another critically important aspect of JavaScript is that it carries
out dynamic binding. Binding refers to the way in which
names of things, such as variable names, function names, and object
names, are associated with the things themselves. If you call
the function dontclickme from listing 3.1 by saying dontclickme(),
you are not actually referring to the function itself, you are
referring to the name of the function. "The Song of the Volga
Boatmen" is really the name of that song, it is not the song
itself. If you want the sheet music, you go to you favorite music
store and ask for it by name; most people do not go in and begin
singing "
Eh-eh uxhnyot..."
There are two general approaches to binding: static binding and dynamic binding. Many languages, particularly compiled languages like C, C++, and Java, often insist on static binding. This means they require that they be able to find all named references when a program is compiled. (Of course, with the advent of dynamically loaded libraries this rule is relaxed a bit.) JavaScript uses the more liberal form, dynamic binding. JavaScript only attempts to resolve names when they are used.
Dynamic binding has several consequences. In the first place,
if the function dontclickme() is never called, then it
can contain all but the most hideous syntax errors and they will
never be found. If dontclickme is the event handler for
a button, and no one ever presses the button, its problems are
never exposed. Even if dontclickme() is absolutely perfect,
but the event handler is erroneously declared to be a function
named noclickme(), this mismatch will not be detected
until someone finally chooses to press the button. JavaScript
will only then try to find a function named noclickme().
It will fail, and an error will result. Dynamic binding is often
called
runtime binding or late binding because the
binding process only takes place when the JavaScript
interpreter
attempts to run the code.
Always check meticulously to ensure that the function, object, and variable names used inHTML match those in the JavaScript code.
Dynamic binding has its advantages and disadvantages. Dynamic binding is used by many interpreters because it simplifies the language, and makes it very easy to add in new functions. Since there is no brooding and melancholy compiler to satisfy, it is possible to build up a complex JavaScript application incrementally. Even if you really need an event handler for every possible event, you can start out with one or two handlers, make them work, and then gradually add more complexity.
The disadvantage of dynamic binding should be clear from the previous
discussion. There is very little error checking. When the JavaScript
interpreter is reading all the code in the SRC URL, or processing
the code between <SCRIPT> and </SCRIPT>,
it is performing some checking but it is by no means performing
an exhaustive analysis of the code. Errors, particularly mismatched
names, are not found until the erroneous code is executed. To
see a more complete example of this, look at the
HTML page defined
in listing 3.2.
Listing 3.2 An Illustration of Dynamic Binding <HTML> <HEAD> <TITLE>A Potentially Dangerous JavaScript Page</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-- function dontclickme() { // button click handler alert("I told you not to click me"); } <!-- end script --> </SCRIPT> </HEAD> <BODY> <FORM METHOD="POST" ACTION="mailto:me@myhost.com"> <INPUT TYPE="button" NAME="mycheck" VALUE="HA!" onClick="dontclickme()"> </FORM> </BODY> </HTML>
If you copy this code, change the e-mail
address in the form's ACTION to your own
e-mail address,
and then read that file into your browser, everything will be
fine. Notice that the click event handler for the button
is declared using the
HTML attribute onClick="dontclickme()",
which tells JavaScript that when this button is pressed the function
dontclickme should be called. (The exact syntax for declaring
event handlers is discussed in the next section.) If you now click
that button you should see something like figure 3.5.
FIG. 3.5 Clicking an HTML button invokes a JavaScript event handler that displays an alert.
So far so good. The name of the event handler in the HTML statement
that created the button matched the name of a
JavaScript function
in the
SCRIPT block. Now try the following experiment.
Change the handler declaration from
to
and then read that file into your browser. You will notice that
the initial appearance of the HTML page is exactly as before.
No errors have been reported. If you attempt to click the button
labeled HA!, your browser reports an error, and the alert dialog
box shown in figure 3.5 does not appear. This is dynamic binding
at work. JavaScript did not know that the function named noclickme
did not correspond to any currently defined function until the
user action forced it to try to find one. Technically, the function
name
noclickme is said to be unbound.
It might seem like dynamic binding is a great potential source of error, without providing many benefits as compensation. As you will see when we discuss objects in Chapter 4, "JavaScript Objects," objects may be defined and even modified on-the-fly. Dynamic binding allows you to refer to things that do not yet exist, but that will exist when the event handler which uses them is actually called. Dynamic binding, like the loose typing provided by JavaScript's var, is a two-edged sword. It must be used with care, but is very powerful.
See the "Defining Your Own Objects" section of
chapter 4 for more information on creating and modifying JavaScript object, p. xx.
Let's summarize these two critical points about JavaScript parsing and execution, since they will dominate our thinking for several chapters to come:
The previous section demonstrated that JavaScript functions are
only executed in response to events. We also know that events
themselves only occur when some interaction with or change to
the current HTML page occurs. There must be a way in which we
can link events to JavaScript functions in HTML. In fact, we have
already seen one such example of this in listing 3.2. The mechanism
is known as the event handler declaration.
Event handler declarations look exactly like ordinary HTML attributes.
Each attribute name begins with the word on and is followed
by the event name, so that onClick is the attribute that
would be used to declare an event handler for the click
event. The full declaration of an event handler looks like
Attribute names are not case-sensitive, following the usual HTML
convention. It is good practice, however, to use the
coding style
shown in the preceding line of code, with on in lowercase
and the event name with an initial capital. This helps to distinguish
it from other attributes, which are often fully capitalized.
The value of the attribute is a set of JavaScript code. The code may be included literally (known as inline JavaScript), or it may reference a JavaScript function. We can completely remove the dontclickme() function of listing 3.2 and write the button statement as
<INPUT TYPE="button" NAME="mycheck" VALUE="HA!" onClick="alert('I told you not to click me');">
This has two disadvantages. First, it tends to lead to very long
HTML statements. There is very little you can accomplish in only
a few characters. If you have hundreds of characters between the
opening (<) and the closing (>) of an
HTML statement it will almost certainly be very hard to read,
and, if it is too long, may cause your browser to choke. It is
also not modular. As you add event handlers for different HTML
elements, you may well find that there is a lot of common code.
Each of the button handlers might use a variation on the same
code. Such common code should always be encapsulated in a JavaScript
function, rather than being repeated in several places.
Declare all event handlers as JavaScript functions. Avoid inline JavaScript code.
One thing to notice about this example is the fact that the value
of the onClick attribute is a quoted string. This follows
standard HTML convention. Therefore, to include a string within
the value of the attribute we must alternate '' quotes with ""
quotes. This follows the JavaScript standard for strings, as we
learned in the "Implicit Data Types in JavaScript" section
of chapter 2. If you modify the dontclickme function
to accept a string argument then you must carefully use quotes
when passing in literal strings. Listing 3.3 shows a modified
version of dontclickme, called
donteventme,
and the
HTML event handler declarations which reference it.
Listing 3.3A JavaScript Function can be Shared by
Several Event Handlers <HTML> <HEAD> <TITLE>An Uncooperative JavaScript Page</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-- function donteventme( str ) { // generic diffident handler alert("I told you not to " + str + " me"); } <!-- end script --> </SCRIPT> </HEAD> <BODY> <FORM METHOD="post" ACTION="mailto:me@myhost.com"> <BR>No<INPUT TYPE="checkbox" NAME="mycheck" VALUE="HA!" onClick="donteventme('click')"> <SELECT NAME="mysel" onChange="donteventme('change')"> <OPTION SELECTED>Nope</OPTION> <OPTION>Not Me</OPTION> <OPTION>No Way</OPTION> </SELECT> </FORM> </BODY> </HTML>
In this example, the function donteventme is called whenever
the
checkbox is checked or any selection is made on the selection
list. The alert function within the
donteventme
constructs an uncooperative message based on the function's string
argument
str. Although this example accomplishes no useful
work, it is a perfect template for a JavaScript page. In general,
a
JavaScript page has the following three components:
You now know how to declare event handlers in general. The next
section shows exactly which handlers can be associated with specific
HTML tags, and gives various examples of how these event handlers
are used.
Netscape Navigator 2.0 has a bug that can prevent
JavaScript event handler code from being triggered. This occurs most often if an IMG directive is given without corresponding WIDTH and
HEIGHT attributes. Make certain that you include these attributes if you are using images together with JavaScript.
JavaScript events occur at three levels-at the level of the entire
Web document, at the level of an individual <FORM>
within the document, and at the level of an element of a <FORM>
within that document. At the same time, any particular element
at any of these three levels may result in more than one event.
For example, you have already seen that text items can generate
up to four different events depending on how they are manipulated.
In this section, we examine each level and see which handlers
are appropriate for the HTML elements within that level. As you
might suspect, most of the action is at the lowest level, within
HTML forms.
The HTML BODY tag is the container that holds the descriptive
content of an
HTML page. Just as the material in the
HEAD
section is about the page, the material between <BODY>
and </BODY> is the page. The
BODY tag
can contain two event handler declarations using the
onLoad
and
onUnload attributes. A
JavaScript page might have
a
BODY declaration that looks like
<BODY onLoad="loadfunc()" onUnload="unloadfunc()">
The onLoad="loadfunc()" attribute declares
a JavaScript handler that will handle the load event.
The load event is generated after the entire contents
of the page, namely the HTML between <BODY> and
</BODY>, has been read, but before it has been
displayed. The
onLoad event handler is an excellent place
to perform any one time initialization. It can also be used to
display a splash screen containing company, product, or copyright
information. It can even launch a security dialog box which permits
only authorized users, with an appropriate password or key, from
completely loading the page.
The onUnload="unloadfunc()" attribute declares
an event handler that is invoked whenever the page is unloaded.
This happens when the user executes any action that brings up
a new page in the same browser window. An unload event
does not occur if a new page is opened in a new window. Even if
a new page is not successfully loaded, the current page is still
unloaded, and the
unloadfunc is called in that case.
An
onUnload event handler can be used to ensure that
there are no loose ends, and to perform any cleanup necessary.
For example, if the user has filled out a form, but has failed
to press the Submit button, the
onUnload handler should
inform the user of that fact. It could even submit the form itself
based on the user's response. Note that both the onLoad
and onUnload handlers are optional.
There is one final document level event handler, although it is
not associated with the BODY tag. Any HTML link can declare
an event handler for the
mouseOver event, which occurs
when the user places the mouse over the HREF of that
link. This can be used to achieve a visual effect, or to perform
some special processing before the user actually tries to access
the link. Listing 3.4 shows a slightly fanciful example.
In the current implementation of JavaScript, links have event handlers, but anchors do not. This means that you must catch navigation events by attaching event handlers to links. If any of your links point to anchors in the same document, the event must be handled at the link, not at the anchor.
Listing 3.4 Using the mouseOver Event to Mediate Access <HTML> <HEAD> <TITLE>A Nationalist JavaScript Page</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-- function warnthem( lnk ) { // mouseOver event handler var theirhost = lnk.hostname; // 2; gethostname of link var domain = "", lastdot = 0, len = 0; len = theirhost.length; // 4; string length of hostname lastdot = theirhost.lastIndexOf("."); // 5; find last dot domain = theirhost.substring(lastdot+1, len); // 6; last part of hostname if ( domain == "zz" ) { // 7; warn about country "zz" alert("Country zz only has 1200 baud modems"); } } <!-- end script --> </SCRIPT> </HEAD> <BODY> <HR> Check out the new links to <A HREF="http://home.std.zz" onMouseOver="warnthem(this)">Zzland</A> and its neighbor <A HREF="http://home.xyzzy.xy" onMouseOver="warnthem(this)">XYville</A> <HR> </BODY> </HTML>
This HTML creates a page with two elements-links to the fictitious
home pages of the countries Zzland and XYville,
and sets up a
mouseOver event handler for those links.
Note that the event handler function
warnthem is called
with an argument this. The special keyword this
is used to refer to the current object. When the
warnthem
function is called, its parameter
lnk is filled in with
the object that represents the link over which the
mouse just
moved.
The this keyword and other object-oriented concepts are discussed in chapter 4 in the section, "Defining Your Own Objects.".
Statement 2 extracts the hostname part of that object, which in
this example could be either home.std.zz or home.xyzzy.xy,
depending on where the mouse is located. The next three statements
use some of the string object functions (see "String Content
Methods," in chapter 4) to tear off the last part of this
fully qualified
hostname, namely
zz or
xy, and
save it in the variable domain. This variable is then
tested against zz in statement 7. If the test passes
then an alert is put up to warn the user that the connection to
the
zz home page will take longer due to slow modems.
Links can also have click event handlers, so this code
can be modified not only to warn the user, but also to abort the
connection, if necessary. The result of placing the
mouse over
the
Zzland link is shown in figure 3.6.
FIG. 3.6 JavaScript event handlers can be used with any hypertext links.
The FORM tag is used to begin the definition of an
HTML
form. It includes attributes from the METHOD to be used
in submitting the form, the ACTION to be taken, and may
also include a single type of event handler attribute, the onSubmit
attribute. The syntax for a
FORM tag is the following:
<FORM NAME="formname" ... onSubmit="submithandler()">
Put event handler attributes last on the attribute list of anHTML tag. This makes them easy to find and modify during debugging.
The onSubmit handler is invoked when the form's contents
are about to be submitted. This is a top level action that applies
to the entire form. It is also possible to specify an
onClick
action on the Submit button in a form, as you shall see in the
section, "Button Click Events." The natural use for
an
onSubmit handler is to validate the contents of a
form. The submission proceeds if the contents are valid, and is
canceled if they are not.
If you return false in an onSubmit event handler using UNIX version 2.0 of Netscape Navigator, it does not cancel the submit.
Listing 3.5 shows a very simple form with a single element, an editable text field. The value of the field is supposed to be a number between 1 and 9. The submit handler function checkit is called when the form is submitted. It validates the user entered quantity and acts accordingly.
Listing 3.5Form Content can be
Validated Using an onSubmit Handler <HTML> <HEAD> <TITLE>A Simple Form Validation Example</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-- function checkit() { // submit validation function
var strval = document.myform.mytext.value; // 2; input text value var intval = parseInt(strval); // 3; convert to integer if ( 0 < intval && intval < 10 ) { // 4; input ok return( true ); // 5; allow submit } else { // 6; input bad - tell user alert("Input value " + strval + " is out of range"); return( false ); // 8; forbid submit } } <!-- end script --> </SCRIPT> </HEAD> <BODY> <HR> <FORM NAME="myform" METHOD="post" ACTION="mailto:me@myhost.com" onSubmit="checkit()"> <P>Enter a number between 1 and 9: <INPUT TYPE="text" NAME="mytext" VALUE="1" SIZE="10"></P> <BR><
INPUT TYPE="submit">
</FORM> <HR> </BODY> </HTML>
It is worthwhile to examine this example in some detail, as it
exposes a number of points that are more thoroughly discussed
later in this chapter. Let us consider the HTML in the <BODY>
first. The FORM statement creates a form named
myform
with our usual fictitious
mailto destination. It also contains
an onSubmit attribute that specifies checkit()
as the JavaScript function to call when the form is about to be
submitted. Like all of our previous event handlers, this one takes
no arguments. You will see very shortly that it is not only possible
to pass in arguments, but it can also be very beneficial. For
a document this simple, however, it is not necessary.
The first INPUT tag establishes an editable text field
named
mytext which can hold up to 10 characters, and
which will be initialized to the string "1".
The second
INPUT tag puts a Submit button just below
the input text field. Neither of these
INPUT statements
have any handler attributes, although they could. What happens
next?
If the user types in any text, or does anything except press the
Submit button, then nothing special happens. This example does
not process any events other than the submit event, so
changes in the text field or navigation actions do not result
in any
JavaScript code being executed. If the user does press
the Submit button, then the myform form tries to submit
itself. This triggers the submit action, which results
in its event handler, checkit(), being called.
The checkit function does two somewhat obscure things.
In statement 2, it sets the local variable strval equal
to the value of document.myform.mytext.value. We know
from the "Functions and Objects" section of
chapter 2 that the right side of this expression must be an object reference-in
fact, a reference to an object within an object within an object.
It is reasonable and correct to assume that the myform
sub-object corresponds to the
HTML form named
myform
within the current document, and that the
mytext subobject
corresponds to the
HTML editable text field named
mytext
inside
myform. This windy construct transfers the value
of that text field into the local variable strval. In
statement 3, an attempt is made to convert this string to an integer
using the built-in function
parseInt. The putative integer
is stored in
intval.
See Chapter 4, "HTML Objects" and "Built-In Functions" for more information on how to manipulate HTML fields.
In statement 4, our validation test is performed. If the string
in the text field did represent an integer between 1 and 9 inclusive
then this if test passes and the checkit function
returns true, in statement 5. This is a message from
JavaScript to the browser that the submission may complete.
If the text field was out of range then the else pathway
in statement 6 is taken. Note that parseInt returns 0
if its argument cannot be parsed as an integer. This means that
if the user entered "five" in the text field
rather than "5" the value of intval
will be 0, and the else clause will be taken. Statement
7 puts up an alert dialog box telling the user that the value
was out of range. It contains the string representation of the
value. This is useful since the alert dialog box may be inadvertently
positioned over the text input field. Finally, statement 8 returns
false, indicating that the submit operation should not
complete. The outcome of entering a value that is out of bounds
is shown in figure 3.7.
FIG. 3.7 JavaScript submit handlers are often used to validate form input.
In this particular case it is important to give the mytext text field an initial value of 1. This ensures that if the user clicks the Submit button without altering that text field it will have an acceptable value, and the form will be submitted. In many cases, just the opposite is true. The whole point of a catalog order form is to persuade the user to enter critical information, such as his name and e-mail address. In this case, it's a good idea to initialize the text field with a deliberately invalid value, so that if the user hits Submit without typing anything the form is not submitted. Chapters 6, "Interactive HTML Objects," and 17, "Creative User Interaction," provide several more sophisticated examples of customized user interaction using JavaScript.
Always give the user meaningful feedback on inappropriate input or other error conditions. Indicate why and where the error occurred, not just that an error occurred. Be brief, but specific.
Almost all form elements may have one or more event handlers. The type of event handlers permitted on a given element depends on the type of element itself. You have already seen the linkage between events and HTML entities in figure 3.4. Broadly speaking, buttons can generate click events, and text and select items can generate focus, blur, select, and change events. The one potentially confusing aspect of this organization of events is that selection lists cannot generate the select event. This is because they have no editable text. We will not consider all possible events in this chapter, only a pithy subset.
There are two important exceptions to the rule that all form elements
can have handlers. The first exception applies to hidden items,
those with <INPUT TYPE="hidden">
. Since
they cannot be seen, they cannot be changed by the user, and therefore
cannot generate events. The second exception applies to individual
OPTION elements within a
SELECT selection list.
The SELECT tag itself may have attributes declaring focus,
blur, and change handlers, but the OPTIONs
may not generate their own events. Any acquisition or loss of
focus, and any change in the item(s) that have been selected applies
to the whole list, not to an individual element.
All button types within an HTML form can have click event
handlers by adding an
onClick attribute to their <INPUT>
declaration. Simple buttons with a TYPE attribute of
"button", "reset" or "submit"
merely signal that they have been pressed. (Recall that the act
of submitting a form may also be caught using an onSubmit
handler attached to the <FORM> declaration.) Checkboxes
and radio buttons also have values. Checkboxes and individual
radio buttons can be asked if they are on or off. A group of radio
buttons can also be asked for the unique index of the button currently
checked.
One very common problem in HTML forms design is the issue of conflicting
options. Users are often presented with a variety of different
choices, which may even be spread out over more than one
HTML
form. Some combinations of choices may be invalid or dubious.
Unfortunately, in standard
HTML there is no way to perform input
validation of this kind without actually submitting the form and
asking the
ACTION URL if that particular combination
is acceptable.
JavaScript event handlers are ideal for this kind of validation.
As you learn in chapter 4, every
HTML form element is also a
JavaScript
object. You have already seen some examples of this in listings 3.4
and 3.5. Listing 3.6 shows two radio buttons working together
with a
checkbox using a
JavaScript onClick event handler. The initial appearance of this form is shown in
figure 3.8.
Listing 3.6 Values of Different Form Elements Can Be Accessed in JavaScript <HTML> <HEAD> <TITLE>Two Choices Work as One</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!--- function insok() { // make sure payment & ins choices are compatiblevar isgold = document.myform.payment[1].checked; // 2;
gold checked
var isins = document.myform.
insurance.checked; // 3;
insurance selected? var ok = null; // 5; if paying in
gold without
insurance then.. if ( isgold == true && isins != true ) { ok = confirm("Do you want
insurance?"); // 6; ask for
insurance if ( ok == true ) { // 7; yes, get
insurance document.myform.
insurance.checked = true; // 8; check it } } <!-- end script --> </SCRIPT> </HEAD> <BODY> <HR> <FORM NAME="myform" METHOD="POST" ACTION="mailto:me@myhost.com"> <STRONG>Payment Options</STRONG><BR> <HR> <
INPUT TYPE="radio" NAME="payment" VALUE="1"
CHECKED onClick="insok()">
Personal Check <
INPUT TYPE="radio" NAME="payment" VALUE="2"
onClick="insok()">
![]()
Gold Bullion <HR> <
INPUT TYPE="checkbox" NAME="insurance" VALUE="Ins">
![]()
Insurance? </FORM> <HR> </BODY> </HTML>
FIG. 3.8 JavaScript onClick handlers can be used to exclude invalid user input.
The <BODY> of this page sets up a two choice radio
button named payment, and a checkbox named
insurance.
The first button is selected, and the
checkbox starts off unchecked.
The radio button group has the function
insok as its
click event handler. Whenever either of the buttons is
clicked the
insok function is called.
In statements 2 and 3 insok fetches the current value
of the second radio button named payment. Note that payment
actually denotes the entire group of buttons, not any single radio
button, so that you must use the array reference payment[1]
in order to refer to the second button (0 based indexing is used).
That value is stored in the
Boolean variable isgold.
The variable
insok gets the state of the
insurance
checkbox, which is also true if it is checked and false
if it is not. A compatibility test is now performed in statement
5. If the radio button group indicates payment in
gold bullion,
but the
insurance button is not checked, then a confirmation dialog
box is put up using the confirm() function in statement
6.
The confirmation dialog box has OK and Cancel buttons. If the
user presses OK, the function returns true; otherwise
it returns false. The return value is tested in statement
7. If it was true, then the user does want
insurance,
and the method function value of the checked
property of the
myform.
insurance object is set to true. Without
worrying too much about what methods and properties really mean
just yet, it is easy to infer that this assignment statement has
the same effect as a click of the
insurance button. That checkbox
is now checked.
TROUBLESHOOTING
I modified the code shown in Listing 3.6. I added another groups of radio buttons to collect information about the user'sincome level, with its own event handler doinc(). I would like to force the insok() function to be called from the new event handler. Inside doinc() I have a statement
This click() function is supposed to cause the insurance checkbox to be checked, but the doins() handler is never called. Why? JavaScript has many functions like click() that emulate user actions. These emulated actions do not generate events, however, so the corresponding event handler functions are never called. There is nothing mystical about the event handler function insok()-it is an ordinary JavaScript function that happens to be linked to an HTML event. If you want to call insok() in your doinc() event handler, just do the following:
HTML text <INPUT> fields with a TYPE attribute
of "text" may declare event handlers for any
combination of the four text events: focus, blur,
change, and select. Multi-line text input items
created with a
TEXTAREA tag may also have these handlers.
Selection lists created with <SELECT> can generate
all these events except select.
The focus event is generated when the text item of list
element gets the input focus, usually as a result of a mouse click.
Tabbing through form fields also moves the input focus. The blur
event is generated when an item which had focus
looses it. The
change event is generated whenever something changes.
In a text item this results when any new text is entered or existing
text deleted. In a selection list it happens whenever a new selection
is made, even in a list that permits MULTIPLE selections.
The select event is generated when the user selects some
text, usually by click-and-drag or double-click operations with
the
mouse. The select event is almost always accompanied
by a
visual cue, usually by the selected text becoming highlighted
or changing color.
These events can be used to obtain very fine control over the content of text or selection list items. The most common application is to use the change or blur events to ensure that a text field has an appropriate value. If you ask the user to enter her birthdate, for example, and provide separate fields for the month, day, and year, you will almost certainly want to make sure that the value of the day field is a number between 1 and 31. You might even go to greater lengths, and limit the day field's value based on the value of the month field. In any case, you want to avoid erroneous input such as "bleen." Text events can also be used to coordinate the values coming from multiple form elements, as we saw in Listing 3.6.
Listing 3.7 shows a linguistic application
of the blur event for a TEXTAREA. The user is
inspired to enter a sentence without a single instance of the
letter e. If the user tries and fails he is chided for his lack
of creativity. Note that the blur event handler is only
called if the user makes an attempt, since blur is only
generated when focus is lost. If the user never clicks or types
in the
TEXTAREA no blur event occurs.
Parts
II and IV of this book provide many more detailed examples of
all the
JavaScript events.
Listing 3.7 An Example of JavaScript's Text Events <HTML> <HEAD> <TITLE>A Literary Exercise</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-- function hasE() { // complain if there is an e var thestr = document.myform.mytarea.value; // 2; gettextarea value var uthestr = thestr.toLowerCase(); // 3; convert to lowercase if ( uthestr == "" ) { // 4; no entry return; // 5; just return } if ( uthestr.indexOf("e") >= 0 ) { // 7; found an 'e' alert("Alors! You've got an E in there!"); // 8; failed } else { if ( uthestr.length <= 20 ) { alert("Nice try, but too brief"); // 11; too short } else { alert("Congratulations!"); // 13; succeeded } } } <!-- end script --> </SCRIPT> </HEAD> <BODY> <P>The novel <I>A Void</I> does not contain a single "e".<BR> Can you create a sentence without one?</P> <HR> <FORM NAME="myform" METHOD="POST" ACTION="mailto:me@myhost.com"> <TEXTAREA NAME="mytarea" ROWS="5" COLUMNS="80" onBlur="hasE()"> </TEXTAREA> </FORM> <HR> </BODY> </HTML>
The modulus operandi of this example should be becoming familiar
to you now. If the user types or clicks in the textarea nothing
happens. When he leaves the textarea and clicks elsewhere a blur
event is generated and the handler function hasE invoked.
This function gets the contents of the
textarea into a local variable
named
thestr (in statement 2) and then uses one of the
string functions to convert it to lowercase (statement 3). This
saves a little time, as the function won't have to test for the
presence of both e and E. The new lowercase string
uthestr
is tested against the empty string in statement 4. If there is
no text the function returns without complaint.
If there is some text, but it has an e the user is reprimanded in statement 8. If there is no e but the text has less than 20 characters the user is encouraged to try a more ambitious work in statement 11. If the text is long enough and has no e then the user is praised in statement 13. Of course, there is nothing preventing the user from entering gibberish such as zzzzzzzzzzzzzzzzzzzzzzzzz and being congratulated anyway. Much more sophisticated checking would be necessary to ensure that the input was actually a sentence.
For technical support for our books and software contact support@mcp.com
Copyright ©1996, Que Corporation