Special Edition Using JavaScript - Events and JavaScript

Copyright ©1996, Que Corporation. All rights reserved. No part of this book may be used or reproduced in any form or by any means, or stored in a database or retrieval system without prior written permission of the publisher except in the case of brief quotations embodied in critical articles and reviews. Making copies of any part of this book for any purpose other than your own personal use is a violation of United States copyright laws. For information, address Que Corporation, 201 West 103rd Street, Indianapolis, IN 46290 or at support@mcp.com.

Notice: This material is excerpted from Special Edition Using JavaScript, ISBN: 0-7897-0758-6. This material is provided "as is" without any warranty of any kind. Please see this DISCLAIMER.

Chapter 3

Events and JavaScript

by Mark Reynolds

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 which 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 on 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 type in 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 quite closely. 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 the user. Even the slightest error will (or should) cause the form to be rejected, so that the form entry must be repeated.

One of the primary goals of JavaScript is to localize most this process, and perform it 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) which are called when something happens. JavaScript functions may be called whenever a form is submitted, or it they 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 which will validate that field whenever the user changes it, and complain if the value is out of range.

This chapter will describe event handling in JavaScript. All the events which may be handled will be discussed, as well as the contexts in which these events may arise. In addition, you will learn how JavaScript may be included within Web pages, and how JavaScript functions are connected with different components of that page. You will learn to:

Events and Actions

In order to understand JavaScript's event handling model we must first think about the set of things which can actually happen on a Web page. Although there are many different things which you can do with the broswer, 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.

In order to understand which browser actions coorespond to JavaScript events, and which do not, it is important to distinguish those actions which actually cause (or might cause) some change in the Web page being displayed. At the top level, the number of such actions is actually quite limited. In fact, there are really only two types of type 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 which can be changed, such as editable text fields.

Navigation Actions and Events

In the navigation category we can distinguish the following different actions:

In most of these cases the current page will be unloaded, which is to say that it will no longer be visible in any browser window. In several of these cases a new page will be loaded, which is to say 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 clicking on a hypertext link need not be successful. The machine to which it points may be down, or simply inaccessible. The link may even be dead, meaning that it does not point to a valid destination. Clicking on a dead link will unload the current page, but it will not load a new page - it will simply result in the browser displaying an error message of some kind.

These events, loading a page and unloading a page, are the two document level events which may be handled by JavaScript. This means that it is possible to write JavaScript code, contained within the HTML definition of a page, which will be executed whenever that page is loaded. You can also have code which is executed whenever that page is unloaded. The dead link example should illustrate the fact that it is important to realize that loading and unloading are two separate, unrelated events. When you attempt to activate a dead link the current page will be unloaded, but nothing will be loaded in its place. In order to retrieve the last good page you must hit the Back button, which reloads that page.

There is two additional events which are vaguely related to nagivation. When you move the mouse over a hypertext link a mouseover event is generated. This event is not associated with clicking on the link, it is instead associated with being poised to click on 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 which will include Visual Basic Script as well as JavaScript. The purpose of this event is to provide staged notifications when a time consuming operations is taking place. For example, if a movie player plug-in was being loaded the statechange event might be issued to indicate the the plug-in was ready to accept some user interaction, but could not yet display its movie.

Forms Input and Events

If you are not using the browser to nagivate the Web, then your only other means of interaction which JavaScript recognizes involves using the interactive elements of an HTML form. Every form element which 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 has a section which is a "Review of HTML Forms"):

Button Elements in Forms

Buttons come in five varieties: simple buttons, yes/no checkboxes, radiobuttons, submit buttons, and reset buttons. Simple buttons are defined using the HTML <INPUT TYPE="button">. Checkboxes are created using an <INPUT TYPE="checkbox"> directive, and define options which are either off (not checked) or on (checked). Radiobuttons 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 which the user has performed; they are specified as <INPUT TYPE="reset">.

Hidden fields on HTML forms do not generate JavaScript events.

The one thing which the four types of button have in common is that you click on the button to acheive its effect. Because this is an extremely common action, and one which has the same meaning in the four cases, the JavaScript event model defines click as one of its HTML form events. In addition when a form is actually submit, a submit event is generated. The submit event is really owned by the form being submitted, and not the submit button which causes it.

Text Elements in Forms

There are three types of text items possible within an HTML form. Single line text fields are created with an <INPUT TYPE="text"> directive, while single line non-echoing text fields are created using <INPUT TYPE="password">. Multiline text fields are created with the <TEXTAREA> tag, and are usually called textareas. 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 ultimately decide you are finished with the text and move on.

What are the JavaScript events which it generates in response to these various actions? JavaScript uses a text manipulation model which will be familiar to anyone who has every used any kind of windowing system. It defines four events which 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 generate JavaScript 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 image map) you can type until your fingers are sore, but nothing will happen. This is a case where nothing has focus.

Selection Elements in Forms

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 will become somewhat clearer later in this chapter, and will be fully clarified in Chapter 6, under "Manipulating Text Fields". Figure 3.1 summaries the events understood by JavaScript and the HTML elements which generate them.

Figure 3.1

JavaScript events model different types of user interaction with a Web page.

Actions Which are Not Events

Anything which was not mentioned in the previous two subsections should be considered an action, and not a JavaScript event. Scrolling a window, reading news groups or answering mail are certainly actions, but they are not events. Using the Back, Forward or Home buttons on the browser's menu bar 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 it does not effect the current page at all. The following rule of thumb may be used to distinguish actions which might possibly be events from those which are not.

If an action will effect or change the current page, then it will be associated with one or more JavaScript events.

It might be argued that scrolling or resizing a window effects 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.

JavaScript Code in HTML

So far we have talked about JavaScript as a language, and we have also talked a bit about HTML, but we have not talked about how JavaScript is used in HTML. Event handlers are the glue, which link HTML elements with JavaScript code, but how is it done? This section will address this question. The answer comes in two parts: how JavaScript is included or referenced in a Web page, and how event handlers are attached to HTML items.

The SCRIPT Tag

In the most general sense, every Web page is constructed from HTML statement which divide the page into two parts: the <HEAD> and the <BODY>. The HTML directives with the context of the <HEAD> given information about the page, while those in the <BODY> make up the page itself. In most simple HTML document the <HEAD> usually contains only the <TITLE>. It can also contain a <BASE> tag which specifies a pathname which 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.

With the introduction to JavaScript and other scripting languages the HEAD section on an HTML document will also contain 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. The reason it that it insures 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 trigger before that code had been read an error would result, as the event handler function would be undefined.

Syntax of the SCRIPT Tag

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 which is used in the subsequent script code; this should be "JavaScript." Strictly speaking, the LANGUAGE attribute is not required; at present only Netscape Navigator is the only browser which is widely available and which 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> may be immediately terminated by a </SCRIPT> directive. A <SCRIPT> block which loaded JavaScript code from a file name click.js in a directory jscode relative to the document base would look like this:

<SCRIPT LANGUAGE="JavaScript" SRC="jscode/click.js">
</SCRIPT>

If the SRC attribute is not given then it is expected that all the code between <SCRIPT> and </SCRIPT> will be the script source itself. In the glorious future, when the overwhelming majority of browsers understand the <SCRIPT> tag, or at least will benignly ignore it, the JavaScript source may be given literally. Until then it is recommended that source which is 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 JavaScript comments // and /* */ inside JavaScript code. Never use HTML 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>

Use of HTML Comments

The function in Listing 3.1 does not do much; it merely uses the alert() function to pop up a warning dialog with its argument as the message. Presumably this function is the click event handler for a button which 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. You should always structure your script according to these 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 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 conformant areas of HTML. Most browsers deviate a little from the HTML standards, and some deviate a lot. The comment rules given above my change in the future, and may be implemented differently on different browsers.

Processing <SCRIPT> Code

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 will not execute the dontclickme() function, it will merely recognize that this function is a JavaScript function, and save 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.

Binding in JavaScript

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 that 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 will never be 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 insure that the function, object and variable names used in HTML 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 make 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 it 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, will not be 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, found in ex32.htm in the js directory on the CDROM with Special Edition Using JavaScript, into a local file, 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 will be discussed in the next section.) If you now click on that button you should see something like Figure 3.2.

Figure 3.2

Clicking an HTML button invokes a JavaScript event handler which displays an alert.

So far so good. The name of the event handler in the HTML statement which created the button matched the name of a JavaScript function in the <SCRIPT> block. Now try the negative experiment: change the handler declaration from

onClick="dontclickme()"
to
onClick="noclickme()"

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 labelled HA! your browser will report an error, and the alert box shown in Figure 3.2 will not appear. This is dynamic binding at work. JavaScript did not know that the function name 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 much in the way of countervailing benefits. As we will see when we discuss objects in Chapter 4, objects may be defined and even modified on the fly. Dynamic binding allows us to refer to things which do not yet exist, but which 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 "Defining Your Own Objects" in Chapter 4

Let us summarize these two critical points about JavaScript parsing and execution, since they will dominate our thinking for several chapters to come:

Declaring JavaScript Event Handlers

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 which would be used to declare an event handler for the click event. The full declaration of an event handler will look like

onEvent="javascriptcode"

Attribute names are not case sensitive, following the usual HTML convention. It is good practice, however, to use the coding style shown above, with the "on" in lower case and the event name with an initial capital. This helps to distinguish it from other attributes, which are often giving 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 could 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 may cause your browser to choke if it is too long. 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 we modified the dontclickme function to accept a string argument then we must carefully use quotes when passing in literal strings. Listing 3.3 shows a modified version of dontclickme, called donteventme, and to HTML event handler declarations which reference it.

Listing 3.3 A JavaScript Function may 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 when 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 whatsoever it is a perfect template for a JavaScript page. In general a JavaScript page will have these three components:

We now know how to declare event handlers in general. The next section will show exactly which handlers may be associated with specific HTML tags, and will give various examples of how these event handlers are used.

Using JavaScript Event Handlers

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. We have already seen that text items may generate up to four different events depending on how they are manipulated, for example. In this section we will 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.

Document Level Event Handlers

The HTML <BODY> tag is the container which holds the descriptive content of an HTML page. Just as the material in the <HEAD> section may be thought of as being about the page, the material between <BODY> and </BODY> is the page. The <BODY> tag may contain two event handler declarations using the onLoad and onUnload attributes. A JavaScript page might have a BODY declaration which looks like

<BODY onLoad="loadfunc()" onUnload="unloadfunc()">

The onLoad="loadfunc()" attribute declares a JavaScript handler which 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 could even launch a security dialog which would permit only authorized users, with an appropriate password or key, from completely loading the page.

The onUnload="unloadfunc()" attribute declares an event handler which will be invoked whenever the page is unloaded. This will happen whenever the user executes any action which would bring up a new page in the same browser window. An unload event will not occur if a new page is opened in a new window. Even if a new page is not successfully loaded, the current page will still be unloaded, and the unloadfunc called in that case. An onUnload event handler can be used to insure that there are no loose ends, and to perform any cleanup necessary. For example, if the user had filled out a form, but had failed to press the Submit button, the onUnload handler to inform the user of that fact, and trigger a submit based on the 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 may declare an event handler for the mouseOver event, which occurs whenever the user places the mouse over the HREF of that link. This could be used to acheive 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.

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; get hostname of link
var domain = "", lastdot = 0, len = 0;
len = theirhost.length; // 4; get string length of hostname
lastdot = theirhost.lastIndexOf("."); // 5; find last dot
domain = theirhost.substring(lastdot+1, len); // 6; get 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. As we shall learn in Chapter 4, in the section entitled "Defining Your Own Objects," the special keyword this is used to refer to the current object. When the warnthem function is called its parameter lnk will be filled in with the object which represents the link over which the mouse just moved.

Statement 2 extracts the hostname part of that object, which in our 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," also 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" homepage will take longer due to slow modems. Links can also have click event handlers, so this code could 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.3.

Figure 3.3

JavaScript event handlers can be used with any hypertext links.

Submit Event Handlers in the <FORM> tag

The <FORM> tag is used to begin the definition of an HTML form. It includes attributes form 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 thus:

<FORM NAME="formname" ... onSubmit="submithandler()">
Put event handler attributes last on the attribute list of an HTML tag. This makes it easy to find and modify them during debugging.

The onSubmit handler is invoked whenever the form's contents are about to be submitted. This is a top level action which applies to the entire form. It is also possible to specify an onClick action on the Submit button in a form, as we shall see below. The natural use for an onSubmit handler is to validate the contents of a form. The submission will proceed if the contents are valid, and will be cancelled it they are not.

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 whenever the form is submitted. It validates the user entered quantity and acts accordingly.

Listing 3.5 Form content may 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 bogus
alert("Input value " + strval + " is out of range"); // 7; tell user
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 will expose a number of points which will be 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 which 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. We 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 it is not necessary, however.

The first <INPUT> tag establishes an editable text field named mytext which can hold up to ten 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 has any handler attributes, although they could. What happens next?

If the user types in any text, or does anything whatsoever except press the Submit button, then nothing special will happen. This example does not process any events other than the submit event, so any changes in the text field, or any navigation actions will not result in any JavaScript code being executed. If the user does press the Submit button, then the myform form will try to submit itself. This will trigger the submit action, which will result 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 hand 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 subobject 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"

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 will pass and the checkit function will return 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 will be taken. Note that parseInt will return 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 zero, and the else clause will be taken. Statement 7 puts up an alert 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 box may be inadvertantly positioned over the text input field. Finally, statement 8 returns false, indicating that the submit operation should not complete.

In this particular case it was important to give the mytext text field an initial value of 1. This insures that if the user clicks on 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 would be a good idea to initialize the text field with a deliberately invalid value, so that if the user hit Submit without typing anything the form would not be submitted. Chapters 6 and 17 will 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.

Event Handlers in <FORM> Elements

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. We have already seen the linkage between events and HTML entities in Figure 3.1. Broadly speaking, buttons can generate click events, and text and select items can generate focus, blur, select and change events. The one potentially confusion 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 may 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 <OPTION>s may not generate their own events. Any acquisition or loss of focus, and any change in the item(s) which have been selected applies to the whole list, not to an individual element.

Button Click Events

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 radiobuttons also have values. Chechboxes and individual radiobuttons can be asked if they are on or off. A group of radiobuttons 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 set of choices in several different forms' elements. 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 we shall learn in Chapter 4 every HTML form element is also a JavaScript object. We have already seen some examples of this, in Listings 3.4 and 3.5 above. Listing 3.6 below shows two radiobuttons working together with a checkbox using a JavaScript onClick event handler.

Listing 3.6 Values of Different Form Elements may be accessed in JavaScript

<HTML>
<HEAD>
<TITLE>Two Choices Work as One</TITLE>
<SCRIPT LANGUAGE="JavaScript">
<!---
function insok() { // make sure payment and insurance choices are compatible
var isgold = document.myform.payment[1].checked; // 2; is gold checked
var isins = document.myform.insurance.checked; // 3; is insurance selected?
var ok = null;
if ( isgold == true && isins != true ) { // 5; if paying in gold without insurance then..
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>

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 will be called.

In statements 2 and 3 insok fetches the current value of the second radiobutton named payment. Note that payment actually denotes the entire group of buttons, not any single radio button, so that we 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 will also be true if it is checked and false if it is not. A compatability 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 is put up using the confirm() function in statement 6.

The confirmation dialog will have OK and Cancel buttons. If the user presses OK the function will return true, otherwise it will return 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 isset 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 on the insurance button. That button will now be checked.


Troubleshooting

I modified the code shown in Listing 3.6. I added another radiobutton group to collect information about the user's income 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

myform.insurance.click();

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() which 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 which happens to be linked to an HTML event. If you want to call insok() in your doinc() event handler, just do it:

insok();


Text Edit and Selection Events

HTML text <INPUT> fields with an TYPE attribute of "text" may declare event handlers for any combination of the four text events: focus, blur, change and select. Multiline 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 will also move 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 will result when any new text is entered or existing text deleted. In a selection list it will happen whenever a new selection is made, even in a list which 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 also 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 insure 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 above.

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 will only be 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 will occur. Parts 2 and 4 of this book will 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; get textarea 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 &quote&quot.<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 will happen. When he leaves the textarea and clicks elsewhere a blur event will be 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 lower case (statement 3). This will save a little time, as the function won't have to test for the presence of both "e" and "E." The new lower case 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 twenty 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 insure that the input was actually a sentence.


Internet & New Technologies Home Page - Que Home Page
For technical support for our books and software contact support@mcp.com
© 1996, Que Corporation