Que Logo

Chapter 14

Fiddling with Forms and Emulating Events


In This Chapter


Welcome to the end of this semester's JavaScript course. You'll close out the day with some fun stuff--just like the last day of class in grade school, when you cracked the windows, broke out the Yahtzee, and ate pizza on the same desk you took math quizzes on. Actually, I'm just fooling. This chapter is about form objects and emulating events, neither of which hold a candle to pizza.

Behind the Form


The form is a staple of virtually any page that interacts with the user. Forms can take the "form" of several incarnations, from buttons to checkboxes to blank text-entry boxes. You will probably want to create JavaScript functions that in some way interpret the data produced by these forms.
Because of our close examination of forms in this chapter, you'll break with tradition and refresh yourself with HTML form tags.
You define a form in HTML with the tag <FORM>. This tag may contain several possible attributes:
METHOD=get or post How to submit form data (get is the default, and it's the usual method).
ACTION=URL Where to submit form data.
TARGET=name of window Which window to display responses to the form in (usually this attribute is left out, unless you want responses to be generated in a new window).
onSubmit="JavaScript code" The event handler for a submit event.

Forms are made up of elements, as they are known in HTML-speak, which the user uses to indicate responses. Form elements include generic buttons, radio buttons, checkboxes, text entries, and Submit and Reset buttons. A form can have any number of these elements in it. An element is defined with the <INPUT> tag, which also takes a series of attributes that define the form element. We can't go into detail for each element, but as a refresher, a typical definition for a button element might look like

<INPUT TYPE="button" name="ad" value="Click to see our Ad" onClick="showad()">


Element and Object
To avoid confusion throughout this chapter, let's clear up the interchange between the terms "element" and "object." A form element, such as a checkbox, is an "element" when you are speaking from an HTML perspective. The same checkbox is also an object, when speaking from a JavaScript perspective. At times, I may seem to use these terms interchangeably-because they do refer to the same ultimate "thing"--but when I say "element," I'm looking at it from an HTML point of view, and when I say "object," I'm considering it from a JavaScript point-of-view.
Any elements defined within one set of <FORM> </FORM> tags are considered to be part of one form. Just as there can be any number of elements within one form, there can be any number of forms within one page.
Within the context of JavaScript, each form element is also a JavaScript object. Therefore, each checkbox, text input area, and so forth has its own set of properties. Although referenced in more detail in the appendix at the end of this book, "JavaScript: The Complete Reference," the properties of these objects are typically parallel to the HTML attributes of the element. There are also properties that contain status information about the element; for instance, the checkbox object contains the property "checked," which contains the current logical status of the checkbox element. Having established all this, let's begin looking at how the forms object works within JavaScript.

Object of Form


The previous chapter briefly mentioned that forms was a property of document. This is true, but furthermore, document.forms is an object itself. Each form within the document is one property of document.forms. This is important, so let's take this concept again slowly.
Remember that a form is defined by anything between one set of <FORM> tags:

<FORM>
form element definitions
</FORM>


Thus, document.forms[0] refers to the first form defined in the document. document.forms[1] refers to the second form; that is, any form elements defined within a second set of <FORM> </FORM> tags somewhere else in the document.
Now, each form in a document is also an object. Therefore, document.forms[0] is an object whose properties are each an element of that form. The elements are referred to in the manner document.forms[x].elements[y]; where x is the form in question, and y is the element within that form.
Imagine that your HTML document contains the following lines:

<FORM>
<INPUT TYPE="button" name="ad" value="Click for Ad" onClick="showad()">
<INPUT TYPE="checkbox" name="married">Are you married?
</FORM>


This form contains two elements: a button and a checkbox. If this is the first form defined in your document, you can refer to its parts in the following manner:
What does it mean when I say, "would contain the definition for the button element"? It means that the value of document.forms[0].elements[0] in this example would be the following string:

"<INPUT TYPE="button" name="ad" value="Click for Ad" onClick="showad()">".


Shortly, you'll see how to refer to specific portions of each element, rather than simply its entire definition.

Properties of Forms


The forms object, like every other object, has a set of built-in properties. Basically, these simply help you to retrieve or modify the main attributes of the form, as follows.

The action Property


This property allows you to retrieve or alter the value of the action attribute of the form in question. For example, perhaps you want to submit the form data to one URL if the user has bought more than a set number of mugs, or another URL if they purchased fewer. You might use the classic if...else statement to change the property documents.forms[0].action. Perhaps, this would take place in a function called buymugs(mugs), which accepts the parameter of how many mugs were bought. The function would be called as an event handler from the event trigger onSubmit, an attribute of <FORM>.
Below, let's play out the code for this scenario:

<SCRIPT language="JavaScript">
function buymugs (mugs)
 {
   if (mugs>=10)
   { documents.forms[0].action = "http://invoice1.htm" }
   else
   { document.forms[0].action = "http://invoice2.htm" }
 }

<FORM method=get onSubmit="buymugs(this.quantity.value)">
<INPUT TYPE="text" name="quantity" ROWS=1 COLUMNS=3>Quantity of order
</FORM>


Looking first at the HTML code, you define a form that contains one element: a text entry box that is three spaces wide. This text entry box is given the reference name "quantity". The FORM definition specifies an onSubmit event handler. It calls the function buymugs() with the parameter this.quantity.value. This construction should seem slightly familiar from Chapter 10. this refers to this whole object-the form-from which you are interested in the property "quantity", which is the specific element within the form named "quantity". value is a property of the text entry object, which contains the user-inputted data.
The function itself is rather the same as previous functions you coded in these chapters. It simply uses an if...else statement to determine a condition and modify the ACTION= attribute of the first form in your document accordingly.

The method Property


Just like the action property, the method property refers to the METHOD= attribute of the FORM definition (don't confuse this property name with the JavaScript function known as a "method"; they are unrelated). You can similarly use this to change the METHOD of a particular form from GET to POST, or vice versa, should you so desire. A function exactly like the one used above would do the trick, as in

documents.forms[0].method = "get"

The target Property


This property allows you to retrieve or modify the TARGET= attribute of the FORM. You use it just like the method and action properties.

Elements, Up Close and Personal


We touched on the fact that the array (or object) elements point to each particular element within a given form. Good. Recall again the example in the form you defined earlier in this chapter: document.forms[0].elements[0] would contain the definition for the button element. Now, the button element in question here also contains several properties of its own. Consider the button element definition again:

<INPUT TYPE="button" name="ad" value="Click for Ad" onClick="showad()">


The button has a name, which in this case is "ad". Thus, you can retrieve or modify its name in JavaScript with a reference to

document.forms[0].elements[0].name


You might assign the value of the preceding line to a new variable, or assign a new string to the line. Each particular form element has its own slightly different set of built-in properties. The button object contains a name property, as you've just seen, as well as a value property. In the case of the button, the value property (as well as the value HTML attribute), is the text that appears on the button itself on-screen. Thus, you can also refer to the value of

document.forms[0].elements[0].value

The checkbox Element


Because each form element serves a slightly different purpose, each object has a slightly different set of built-in properties. Let's consider the checkbox element, defined in a way such as:

<INPUT TYPE="checkbox" name="marstat" onClick="married(this.marstat.value)">Married?


Let's imagine that the preceding is the second element of the same form that contains the previous button, thus making it documents.forms[0].elements[1]. The name property of this checkbox object works the same way as the name property of the button object.
The checkbox object also contains two unique properties: checked and defaultChecked. These are logical values that, when assigned a true or false value, determine the starting state of the checkbox, before the user gets his hands on it. Sometimes, you might want a checkbox to begin in a checked state; you can do so either in the HTML definition of the element, or by assigning a true value, as in the following:

documents.forms[0].elements[1].checked = true.


Note that the value property works differently for the checkbox than for the button. In the preceding checkbox, the property documents.forms[0].elements[1].value is a Boolean that contains the state of the checkbox. This is what you would refer to if you were processing this form. Note, in the onClick call in the preceding example, how you call the hypothetical function married(this.marstat.value).

The this Object


One of the most important constructions with which you refer to form elements is the this construction. By now, you've seen it pop up several times. Take an official look at it now.
Clearly, a construction such as document.forms[0].elements[1].value is somewhat long and unwieldy. However, when you are referring to form elements from within a particular form definition, you don't have to use such a long construction.
If you are between <FORM> </FORM> tags, the form to which you are referring is a given: this form. Therefore, document.forms[x] can be assumed.
Secondly, you can refer to individual form elements by their name, rather than elements[y], which makes more sense to the human programmer. Thus, the first element-a button-in your continuing form example from above, could be called elements[0] or it could be called ad. Recall that you named it ad with the NAME= attribute.
Therefore, when you refer to a form from within its definition-which you do anytime you define an event handler for the form or element-you can use the simpler construction this.elementname.property.
You've seen this in practice a few times. Here's an example that combines a couple of your previous this uses:

<FORM onSubmit="evalform(this.email.value)">
<INPUT NAME=email TYPE="text" ROWS=1 SIZE="20">Enter your email
<INPUT NAME="marstat" TYPE="checkbox" onClick="married(this.marstat.value)">Married?
<INPUT NAME=submit TYPE="submit">
<INPUT NAME=reset TYPE="reset">
</FORM>


When in Doubt, Be Specific
I have found some inconsistencies to the way JavaScript handles this in practice, versus how it claims that it should be handled. The simplest solution to any strange errors or difficulties with this is simply to replace the use of this with document.forms[x].
Two event handlers are defined in the preceding form. One handles the onSubmit event and passes to its function the parameter this.email.value. That, then, would be the data entered (value) into the form element email (the text box defined in the second line of the example).
The second event handler occurs in the onClick event of the checkbox element. It passes to its function the parameter this.marstat.value, which would contain the Boolean state of the checkbox named marstat.
Keep in mind, though, that this works only from within the form definition. If you want to refer to a form other than the one currently being defined, you'll need to use the full document.forms[x].elements[y] construction. That's the only way to explicitly specify which form or element you are talking about to JavaScript. The this construction is basically a shortcut for those instances when it can be assumed which form you're talking about.

The Faked Event


Remember that an "event" usually occurs when a user clicks on something. There are a variety of possible events, depending on what the user clicks on. It is possible to emulate a click in JavaScript.
Meaning? If you have a checkbox element, you could instigate a click on it yourself with JavaScript code, rather than waiting for the user to click on it manually. Why would you want to do this? I don't know. Just kidding-actually there are a couple of possible reasons:
Imagine that you have the following two elements in your form: a checkbox, which poses the question, "Do you like spicy foods?" and a radio button set, which asks the user to choose which spicy food is his favorite. The radio buttons offer three choices: "Mexican," "Indian," and "I said I didn't like spicy foods."
Suppose the user unchecks the checkbox, indicating a lack of enthusiasm for spicy foods. In that case, it would be nonsensical for the user to then check one of the regional food types in the radio button set. But how can you prevent the user from saying he doesn't like spicy foods but his favorite spicy food is Indian?
Using event emulation! (Boy, you knew that was coming, I hope.) This would be the programming logic:
This way, no matter what the user tries to select in the radio buttons, his selection will be overridden if it conflicts with a previous selection.
You will code the above logic shortly. First let's see how to emulate an event.

It's All in the Method


Event emulators are methods of the form element objects. Each of the form element objects has a click() method. Simply call this method for the object in question and it will be clicked. Therefore, to click a checkbox, you might use the call

document.forms[0].checkboxname.click()


Important note: A click() method does not initiate an event trigger. Only a "real" click on the checkbox would trigger the onClick event handler, if defined. If you want to emulate a click and trigger the appropriate event call, simply call the proposed event handler manually after the click() method. For example, let's say your onClick event handler is defined as "married(this.checkbox.value)". If you want to emulate a click and call the event handler, simply use the JavaScript statements

document.forms[0].checkboxname.click() ;
married(this.value)


All you did was call the event handler explicitly following the emulated click, since it would not have been triggered by the onClick definition.
Before you run through example code for the "spicy food" logic, remind yourself how radio buttons work. A radio button is basically a multiple-choice question, from which the user can select only one of the proposed choices. What makes the radio button slightly different from other form elements is that it may contain several subelements-that is, the radio button named "spicetype" could have three subelements, each representing a choice: Mexican, Indian, or Don't like.
The following is the HTML code wherein we define the checkbox and radio buttons for our spicy foods example.

<FORM>
<INPUT NAME="spicy" TYPE="checkbox">Do you like spicy foods?<p>
Please select which spicy food is your favorite:
<INPUT NAME="spicetype" TYPE="radio" value="mexican" onClick="checkspicy(document.forms[0].spicy.checked)">Mexican
<INPUT NAME="spicetype" TYPE="radio" value="indian" onClick="checkspicy(document.forms[0].spicy.checked)">Indian
<INPUT NAME="spicetype" TYPE="radio" value="notype" onClick="checkspicy(document.forms[0].spicy.checked)"> I said I don't like spicy foods!
</FORM>


Note how each part of the radio button is defined to the same NAME= attribute. This is important. Also, see how each radio button definition contains the same onClick event handler. Therefore, any time a user makes a choice from the radio button, the verification function checkspicy(document.forms[0].spicy.checked) will be called. This is the heart of our logic.
The function's role will be to look at the Boolean (logical) state of the checkbox named "spicy" (document.forms[0].spicy.value) and either allow the user's radio button selection to remain, or force a different selection. You would force a different selection under two conditions:
Here is the function code in JavaScript:

<SCRIPT language="JavaScript">
function checkspicy (likes)
{
  if (likes == true)
   { if (document.forms[0].spicetype[2].checked == true)
      { document.forms[0].spicetype[0].click() } }
  else
   { if (document.forms[0].spicetype[2].checked == false)
      { document.forms[0].spicetype[2].click() } }
}
</SCRIPT>


Use the construction spicetype[x] to refer to an individual choice x within the radio button set. Here, first consider whether spicy is checked true. If so, look to see if the last radio button choice (button number 2, since they start counting from 0) is selected. If so, it should not be (because the user indicated that he does like spicy foods), and so you emulate a click event to check "Mexican" (radio button choice 0).
If the user has indicated a distaste for spicy foods, look at the else clause above. Here, determine if the final radio button choice has been selected. If not, you emulate a click event to select it, because it must be selected in this case.

All Together Now


The tools provided throughout these chapters should serve as a good overview of JavaScript and its applications. I've avoided delving into highly complex programming examples, in part because this is an introduction to the language, and in part because such examples are more about programming science than the JavaScript language itself.
The best way to learn a programming language is, as my irritating piano teacher used to say: Practice, practice, practice. And experimentation, although she didn't ever mention that. You'll need to read these chapters multiple times, in different manners. For the first read-through, you might look to pick up the general concepts behind JavaScript programming. On a second read-through, perhaps focus on the specific syntax of the JavaScript statements and expressions.
Then, at each example, attempt to throw together your own code that is just a slight variation on the example. See if it works, and if so, vary it further with new ideas. Eventually, you work toward combining concepts from multiple examples, and before you know it, you're constructing your own programs from scratch.
One word of advice is not to be beset by frustration when programs don't work the first time through. Errors and malfunctions are the stuff that programs and programmer's lives are made of. Sometimes, the error is caused by something silly, such as forgetting a closing bracket or parentheses. Other times, you haven't a clue why the program is not working. In those cases, it's a good idea to try other approaches to the end, and see if they work. Or just scream. There is a whole science to debugging-which is of great value to learn if you become heavily involved in programming-but when all else fails, I always recommend the "clear head" approach. That is, walk away. Come back another day. Many dastardly bugs are solved this way. The rested, clear mind can solve some problems in minutes that the haggard mind struggles with for hours. A perusal through Chapter 20 might be recommended, as well, where you'll find some further consideration given to script debugging and pest extermination.
Given that not-exactly-a-pep talk, you're off and programming!

The Least You Need To Know


Previous Chapter Next Chapter



Beginning of ChapterTable of ContentsBook Home PageQue Home Page


For comments or technical support for our books and software, select Talk to Us.
To order books, call us at 800-716-0044 or 317-228-4366.
© 1996, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon & Schuster Company.