reptile7's JavaScript blog
Sunday, July 24, 2005
 
Properties VI: Form Control Elements
Blog Entry #17

As detailed by the Forms sector of the HTML 4.01 Specification, there are at least twelve types of form controls, which we can put into three categories:

(1) Field-type controls, for which the user inputs information, usually a text string, into a rectangular box, including:
(a) the text box;
(b) the textarea box;
(c) the password box;
(d) the file select box;
(e) the hidden field, for which the form author does the inputting, also belongs in this category.

(2) Menu-type controls, for which the user chooses one or more options on a list of items, including:
(a) the radio button;
(b) the checkbox;
(c) the selection list.

(3) Button-type controls, including:
(a) the general push button;
(b) the non-image (regular) submit button;
(c) the image submit button;
(d) the reset button.

As noted in the last entry, we want to be able to utilize a user's responses to a form in JavaScript command statements. In this regard, we are mostly interested in the field-type and menu-type controls, which constitute the meat of a form in relation to user input and, moreover, whose name and value information would be sent to the processing agent if/when the form is submitted.

Each of the controls above is represented in JavaScript by a specific, corresponding object - a Text object, a Textarea object, a Password object, etc. - except for the image submit button*. With respect to the manipulation of form information by JavaScript, we have two general concerns:
(1) How do we refer to form control elements in JavaScript command statements?
(2) How do we determine the user's input?
As you can guess, we will use the properties of form control objects to answer these questions.

*Although supported by Netscape 4.x, the <input type="image"> element has no 'reflection' in JavaScript 1.3's set of client-side objects. Re the following section, programmatic access to this element is browser-dependent on my computer: MSIE/JScript treats it normally but Netscape/JavaScript doesn't recognize it at all.

Referencing form control objects

Each type of form control can be referenced in JavaScript as a member of a form's elements[ ] collection:

document.form_name.elements[i].property_or_method

And except for groups of radio buttons and checkboxes with the same name, each type of form control can also be referenced by its name:

document.form_name.control_name.property_or_method

The name of a control is usually preset by a name="control_name" attribute in the control element's opening HTML tag. However, each type of form control object has a read/write name property that can also be used to set the control's name.

A group of radio buttons or checkboxes with the same name constitutes a control_name collection of the containing form, and the individual radio buttons or checkboxes of the group can be referenced as a member of this collection. For example, consider a form with three radio buttons:

A
B
C

<form name="fr">
<input type="radio" name="letter" value="A"> A<br>
<input type="radio" name="letter" value="B"> B<br>
<input type="radio" name="letter" value="C"> C<br>
</form>

The first radio button can be referenced as:

document.fr.letter[0].property_or_method

The second radio button can be referenced as document.fr.letter[1].property_or_method, etc.

Unlike radio buttons, the individual checkboxes of a checkbox group do not need to have the same name, and if you were to assign different names to these checkboxes, then each checkbox can be referenced by its name, as for other types of controls. Moreover, a solitary radio button or checkbox in a form can also be referenced by its name.

(Note: a group of radio buttons with the same name is supposedly "stored as a single element of the elements array of the Form object" (to quote DevGuru's Radio object page); this isn't how it works on my computer (a Windows implementation, perhaps?), which gives identical returns for document.form_name.radio_group_name[i].property and document.form_name.elements[i].property commands for the same value of i, as shown in the "Radio Button User Input Test Div" demo below.)

Determining user input: field-type controls

The all-important property of all of the field-type control objects that determines - indeed, constitutes - a user's input is the value property. Let's illustrate with a simple example; type your first name into the text box below, and then click outside of it:

Please tell us your first name:

The code for this is:
<form name="fv">
Please tell us your first name: <input name="tv" onblur="window.alert('Glad you could stop by, ' + document.fv.tv.value + '.');">
</form>

in which the command:

document.fv.tv.value

returns the value, or user input, of the text box named tv, in the form named fv, in the document.

Next question: how do you ensure that the user's input is legitimate? Suppose you are running an e-business; how do you prevent the user from entering a six-digit number into the zip code field on your shopping cart page? Now we are getting into the realm of data validation, a topic that is beyond the scope of this blog entry but that we'll get a taste of in HTML Goodies' JavaScript Primers #29.

Determining user input: selection lists

It's easier to determine user input for a selection list than for a group of radio buttons or checkboxes, so we'll deal with selection lists first. The two key properties of the Select object relating to user input are the options property, which represents the collection of option elements composing the selection list and allows us to access those <option>s, and the read/write selectedIndex property, which sets or returns the index number (0, 1, 2, ...) of the currently selected option of the options[ ] collection. (Unique among the form control objects, the Select object does not have a value property.) To complete the picture, we then turn to the JavaScript Option object, whose read/write text property sets or returns the text of a given <option>. We put it all together in two lines of code:

var si = document.form_name.select_name.selectedIndex;
var user_input = document.form_name.select_name.options[si].text;

or one line, if you prefer:

var user_input = document.form_name.select_name.options[document.form_name.select_name.selectedIndex].text;

In summary, we first determine the index of the selected option and then plug that number into the options[ ] collection to determine the text of the selected option. Try it out with the demo below:

Choose your favorite day of the week from the selection list below:

The code for this is:
<form name="fs">
Choose your favorite day of the week from the selection list below:<br>
<select name="favday" onchange="var si = document.fs.favday.selectedIndex; window.alert(document.fs.favday.options[si].text + ' is my favorite day, too!');">
<option>Monday</option>
<option>Tuesday</option>
<option>Wednesday</option>
<option>Thursday</option>
<option>Friday</option>
<option>Saturday</option>
<option>Sunday</option>
</select>
</form>

Determining user input: radio buttons and checkboxes

When a HTML form is submitted, the values of its user-chosen radio buttons, checkboxes, and selection-list options (and of its other "successful controls") are sent to the processing agent. In JavaScript, however, there is no relation between the value property of the Radio, Checkbox, and Option objects and whether the corresponding control elements are 'switched on'.

Moreover, for collections of radio buttons and checkboxes, there is unfortunately no collection-wide selectedIndex-type property that returns the index number of a chosen radio button or checkbox, and even if there was such a property, it would probably have only limited utility with checkboxes; when a selection list is set up with the multiple attribute to allow more than one option to be selected, selectedIndex only returns the index of the first selected option.

The Radio and Checkbox objects do at least have a checked property that returns true if the corresponding control is checked and false if it isn't (the Option object has an analogous selected property). To determine the user input for a group of radio buttons or checkboxes, then, a trial-and-error approach is required; we're going to have to go through the group and determine the checked status of each radio button or checkbox. This might sound like a complicated or tedious process, but it actually isn't. We'll need to use a for loop - the for loop is introduced in Primer #24 - and an if conditional statement - if statements are introduced in Primer #13 - so yes, we'll be getting ahead of ourselves once again, and yet only three lines of code are required, so I'm going to give you the lowdown anyway.

The div below illustrates the determination of user input for a group of radio buttons in a form named fr2.

The Radio Button User Input Test Div

Choose a color below and then click the "You have chosen..." button.
Red
Orange
Yellow
Green
Blue
Indigo
Violet
Black



The code that is triggered by clicking the "You have chosen..." button is: for (var i = 0; i < document.fr2.length; i = i + 1) { if (document.fr2.elements[i].checked) { document.fr2.elements[9].value = document.fr2.elements[i].value; } } Very briefly: (1) The first line sets up a repeating block of code that runs according to a counter variable i. The block of code, delimited by braces, will repeat as long as i is less than document.fr2.length (10 in this case). The value of i is initially set to 0, and i increases by 1 at the end of each run through the loop; when i progresses to 10, the loop stops. (2) The second line asks the question for each value of i: is document.fr2.elements[i].checked true? If so... (3) The third line assigns the value of document.fr2.elements[i] to that of document.fr2.elements[9], the text box to the right of the "You have chosen..." button. (The value of each color-choice control is set to the text following the control.) You may be wondering, "Instead of this for loop business, can't we just add an onclick='document.fr2.elements[9].value = document.fr2.elements[i].value;' attribute to each <input type='radio_or_checkbox'> tag of the form?" In this case, the answer is yes for radio buttons but no for checkboxes. Consider the Black checkbox that concludes the list of color choices. You can click this checkbox and then click the "You have chosen..." button, and "Black" will appear in the text box - so far, so good. But if you reclick and thereby unselect the Black checkbox without making a subsequent choice (radio buttons do not toggle in this way), then the value of the text box is still "Black", which is obviously problematic vis-à-vis determining the user's input. Other properties OK, these are not the only properties of form control objects. But the other control object properties are less crucial. For example, each type of control object has a form property that returns a reference to the form containing the control. In practice on my computer, control_object.form returns "[object FORM]" when using MSIE and "[object HTMLFormElement]" when using Netscape, regardless of whether the form is named or not named. Finally, each type of control object has a type property, which is self-explanatory for the <input> control objects: text_object.type returns "text", radio buttons return "radio", etc.; Textarea objects similarly return "textarea". Curiously, general push buttons that are coded by <button> (as opposed to <input type="button">) return "button" and "submit" for the type property when using MSIE and Netscape, respectively. A Select object returns a type of "select-one" or "select-multiple" for a <select> element without or with a multiple attribute, respectively. I find that the type property is read-only when using MSIE but is read/write in some cases when using Netscape. For example, I am able to click a radio button into a checkbox with the following code: <input type="radio" onclick="this.type='checkbox';"> (The this keyword was briefly discussed in Blog Entry #8.) I am likewise able to change (a) a text box into a password box or a file select box, (b) a regular submit button into a reset button, and even (c) a submit button into a text box or a radio button. However, my attempts to change a text box into a radio button or a submit button caused the browser to crash.
We're just about ready to wrap up our discussion of JavaScript properties, at least for the time being, and move on to Primer #8. I still want to go over some of the properties of the window, History, Location, and Date objects - I don't know if I'll cover them all in one post - I'll start writing and then see how it goes.

reptile7

Thursday, July 14, 2005
 
Properties V: Form Elements
Blog Entry #16

Up to this point, I've been a bit sloppy in my use of the phrase "form element", so let's tighten up the terminology here. With respect to an HTML form, form element really refers to the containing element that begins with <form> and ends with </form> - fair enough, eh? The elements that compose a form - text boxes, radio buttons, selection lists, submit buttons, etc. - are termed controls, and hereafter we will call them "form control elements".

Forms crop up regularly in the JavaScript material at HTML Goodies; however, at least for the short term, we won't be sending them from point A to point B across the Internet. Instead, as will become clear, forms will serve as an important part of our JavaScript toolbox of interactivity. Specifically, we will solicit input from the user via form control elements and then feed the results into JavaScript command statements in order to do cool things.

Form elements, themselves

In analogy to an <img> element, a <form> element can be referenced in JavaScript as either a member of the document forms[ ] collection or by its name, i.e.,

document.forms[index number or name string].property_or_method    or    document.form_name.property_or_method

in which form_name is the value of the name attribute held by the <form> tag. (DevGuru's document object page specifically lists a formName property for the document object.)

On their respective JavaScript Form object pages, DevGuru and JavaScript Kit list identical sets of seven form object properties:

action, elements, encoding, length, method, name, target

The most important of these properties for our purposes is the elements property, which represents a built-in array of the form control elements composing a form; in much the same way that forms[ ] is a document object collection, elements[ ] is a Form object collection. Like the document forms property, the Form elements property is not meant to be returned but is used to refer to the control elements of a form in JavaScript expressions. Let's suppose that you author a Web page containing a single form that comprises a text box A, followed by a selection list B, and finally a submit button C. We can reference these controls as follows:

text box A: document.forms[0].elements[0].property_or_method
selection list B: document.forms[0].elements[1].property_or_method
submit button C: document.forms[0].elements[2].property_or_method

The action, encoding, method, and target properties relate to the sending and processing of a form; they are all read/write. Very briefly:

• The action property specifies the URL to which the form will be sent for processing; for example, at the HTML Goodies home page, document.forms[0].action would currently read: http://search.internet.com/htmlgoodies.earthweb.com (the value of the action attribute for the first <form> on the page).

• When a form is sent via HTTP to its processing agent, its data is encoded according to a particular MIME type; it follows that the Form encoding property specifies a form's MIME type encoding, which in HTML can be preset via the enctype attribute of the <form> tag; at the HTML Goodies home page, document.forms[0].encoding would read: application/x-www-form-urlencoded (this is the default value of the (optional) enctype attribute, which, you'll note from the source code, is not used in any of the page's <form>s).

• The method property specifies whether the GET or POST HTTP request method is used to send the form to its processing agent; at the HTML Goodies home page, document.forms[0].method, document.forms[2].method, and document.forms[3].method will all return "post", whereas document.forms[1].method will return "get".

• Similar to the target property of the Link object, which we briefly discussed in Blog Entry #14, the Form target property specifies the window or frame to which the form's output, if any, is sent.

When this post was first written I presented a form target demo utilizing an EarthLink appendto CGI script that collects data from an HTML form, writes the data to a separate file, and then pops up a "thank you" page for the user. As I am no longer an EarthLink subscriber, a div-based facsimile of the original demo is given below:

Lunch Survey

1. Please tell us your first name:

2. For making a sandwich, what type of bread do you prefer?
White
Wheat
Rye
Pumpernickel

3. And what would you have along with your sandwich?





The processing of HTML forms is an interesting, if somewhat involved, topic, and HTML Goodies discusses several approaches thereto, including the use of CGI/Perl, ASP (active server pages), and PHP (hypertext preprocessor). Annoyingly, EarthLink doesn't seem to support PHP - I tried to execute the test script here in files with .php, .php3, .php4, and .phtml extensions at my EarthLink Web server space, without success - nor does EarthLink allow its basic subscribers to put custom CGI scripts on its server machines; otherwise, I would be tempted to address form processing in more detail.

Getting back to Form object properties, the length property, which is read-only, can be used in a couple of different ways. Like the length property of the document links collection (discussed in Blog Entry #13), the expression

document.forms.length

returns the number of forms in the document body. On the other hand, the expression

document.forms[i].length

returns the number of control elements in the ith form on the page. At the bottom of the left side of the above demo is a small script that reads the Form length property in both of these ways. With respect to the document.forms['formdemo'].length return, the nine control elements, in order, are two hidden inputs, a text box, four radio buttons, a selection list, and a submit button. Note that each radio button is indexed as a separate control, and that the option elements of the selection list are not included in the element count.

Finally and anticlimactically, the Form name property specifies a form's name; it is read/write.

We'll address the properties of form control elements in the next entry.

reptile7

Monday, July 04, 2005
 
Properties IV: The Image Object
Blog Entry #15

References
(1) HTML Goodies' general comments on images and image formats
(2) DevGuru's <img> tag page
(3) JavaScript Image object pages:
          (a) DevGuru
          (b) JavaScript Kit
          (c) IRT

Needless to say, the display and manipulation of images are a central part of the Web. In the context of JavaScript, the images on a Web page constitute a document object collection, to use IRT's categorization, and in turn, each image is an object with its own properties. In analogy to a link, an image can be accessed by a document.images[i] reference, e.g.:

document.images[0].relevant_property = "suitable_value";

We'll see in HTML Goodies' JavaScript Primers #8 that an image can also be referenced, somewhat more user-friendlily, by its name:

document.image_name.relevant_property = "suitable_value";

in which image_name is the value of the name attribute held by the image's HTML <img> tag.

In this post, I will briefly address some of the changeable features of images, including:
• identity of an image (name and source)
• dimensions of an image (width and height)
• positioning of an image (hspace, vspace, etc.)
• the image border
Seven of the nine Image object properties listed at DevGuru's Image object page are specified as "read-only" (JavaScript Kit and IRT are less clear in this regard). But are they really? Ever the optimist, I set out to see if I could write these "read-only" properties; I am pleased to report that in most cases I was successful.

Image Identity

The Image name property, which specifies the name attribute of an image's <img> tag, can be written, even on the fly, if for some reason you wanted to do that. Much more interesting is the also-writable Image src property, specifying the <img> src attribute whose value is the 'source' or URL of the image. Bearing in mind that an <img> element represents not so much an image as it does a placeholder for an image, we can use the same space on a Web page for different images by changing the value of the src property, a process informally termed "image flip". Several of the later HTML Goodies JavaScript primers feature image-flip scripts, including Primers #27 and #28, which present scripts for a JavaScript slide show and for a JavaScript animation, respectively, so we'll hold off an image-flip demo until then.

Presumably the Image lowsrc property should be writable as well; Joe has a tutorial on lowsrc images here.

Image Dimensions

I find that the Image width and height properties can be written dynamically when using either MSIE or Netscape. I have put together a demo that demonstrates the writing of these and other Image properties. The code for the button that changes the width and height of the thumbnail photo is:

<input type="button" value="Click here to change the image width and height." onclick="document.images['catImg'].width='430'; document.images['catImg'].height='330';">

The Image Properties Demo

Below is a thumbnail photograph of Alli, the sleeping kitty.

Meow!













Image Position

As noted by DevGuru, an hspace attribute in an <img> tag can be used to add horizontal blank space between an image and whatever is to the left and the right of it; similarly, a vspace attribute can be used to add vertical blank space between an image and whatever is above and below it; these attributes are somewhat analogous to the cellpadding attribute of a <table> element. The corresponding JavaScript hspace and vspace properties can both be written, although the implementation thereof on my computer is browser-dependent. When using MSIE - this may sound strange and I'm at a loss to explain it - I have found (admittedly by accident) that I can write the hspace and vspace properties IF I also change the value of the Image border property. For example, the code for the button that sets dynamically the hspace property of the thumbnail photo in the above demo is:

<input type="button" value="Click here to increase the image hspace." onclick="document.images[0].hspace='40'; document.images[0].border='1';">
(The <img> border is initially set to "0".)

With Netscape, it's not necessary to reset the border; the document.images[0].hspace='40' command by itself will increase the hspace.

But maybe you want to add more space to just the left side of an image and not the right side, or to just the top and not the bottom (or vice versa). Well, the style object and its properties - specifically, the margin-left, margin-right, margin-top, and margin-bottom properties - to the rescue! The demo code for the button that increases only the left margin of the thumbnail photo is thus:

<input type="button" value="Let's set a larger left margin." onclick="document.images[0].style.marginLeft='80px';">

Joe discusses and demonstrates an alternate approach to the positioning of images with style commands in his "So, You Want Positioning, Huh?" tutorial. To set the pixel coordinates (relative to the origin of the document content area) of the upper-left-hand corner of an image, he uses the following code:

<img style="position:absolute;top:35px;left:170px;" src="circle.gif">

Joe concedes: "position:absolute; states that the image will go exactly where I say it will. If text or another picture is already there -- tough. This will go right over top of it. That is one of the drawbacks to this positioning stuff." This overlay problem won't happen, however, if you use margin-left and margin-top instead of the position, left, and top properties.

BTW, the x and y Image properties listed on IRT's Image object page return respectively the left and top pixel coordinates of an image, regardless of how (or whether) the image was positioned. The x and y properties are supported by Netscape but not by MSIE, and are read-only.

Image Border

As is clear from our discussion of the hspace/vspace properties above, the Image border property is writable. Relatedly, Joe outlines the creation of variously styled borders in his "CSS and Borders" tutorial. The demo code for the button that puts a fancy border around the thumbnail photo is thus:

<input type="button" value="Let's put a fancy border around the photo." onclick="document.images[0].style.border='dotted indigo 10px';">

Image Loading/Visibility

I even took a stab at writing the Image complete property, which returns true if an image has completely loaded and false if it hasn't. I put:

onload="document.images[0].complete=false;"

in the document <body> tag to see if I could prevent the Alli photo from loading - no luck/error. (MSIE: "Object doesn't support this property or method"; Netscape: "Setting a property that has only a getter".)

However, it is possible to hide a loaded image and then have it appear in response to a user event by initially setting the image's style.visibility property to "hidden" and then changing it to "visible", as demonstrated below.

Image Visibility

This demo is for the dog lovers out there. Woof!

Roll your mouse over these words to visualize a photo of Cali, the German shepherd.


It was my original intention to also discuss the properties of form elements in this post, but then I thought, "Y'know, Image properties really deserve their own entry," so we'll get to forms next.

reptile7


Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)