It is often necessary to be able to get or set values of form fields. While it's possible to do so in a cross-browser fashion, you must be careful to use the correct functions and attributes.
This page will only work on browsers which support the DOM and have Javascript enabled. The form on the left will allow you to make changes (except in the fields which show the selected value for the radio buttons or the drop-down menu) which are reflected in the form on the right.
The event objects are retrieved using the procedure demonstrated in the Javascript Events snippet.
In code examples below, it is assumed that obj
is the object
which triggered the event.
The contents of a text field or text area can be retrieved or set using the
.value
attribute:
var contents = obj.value; // Retrieve value obj.value = 'New contents'; // Set new value
When the contents of a text field are changed, an onchange
event is triggered. Unlike other form fields, you must attach the
onchange
event handler directly to the input field
or text area, either
with an onchange
attribute or via Javscript. For example:
<input type="text" name="textfield" onchange="textchanged()"/> <textarea name="textarea" onchange="textchanged()"></textarea>
The status of a checkbox is reflected in the boolean attribute
.checked
:
var ischecked = obj.checked; // Retrieve value obj.checked = true; // Force checked state
When the form is submitted to the web server, the .checked
attribute is sent when the checkbox is in the checked state, and
it isn't sent when the checkbox is in the unchecked state. You can retrieve
or change this value with the .value
attribute, as with
text fields.
An onclick
event is triggered when the checkbox is clicked.
If your event handler returns false
, the state of the checkbox
will not change on Internet Explorer or Mozilla (and other Gecko-based
browsers). On Safari, however, the event handler's return value is
ignored.
Radio buttons are different than other form objects since there are multiple objects which aren't in a hierarchy. Instead, the objects are distinct, but happen to share the same name. For example:
<fieldset id="radios"><legend id="foo">Choose a letter:</legend> <label><input type="radio" name="letter" value="one"/> A</label> <label><input type="radio" name="letter" value="two"/> B</label> <label><input type="radio" name="letter" value="three"/> C</label> </fieldset>
The radio buttons are logically grouped with
<label></label>
tags, as is the description for
each choice. When the form is submitted, the variable letter
will
be passed with the value of the selected radio button, or in this case, either
one
, two
, or three
. We also group the radio
buttons with a fieldset container which we can later find. The fieldset also draws a box around the buttons, further emphasizing that they are a group.
As with checkboxes, the .checked
attribute shows
whether a particular radio button is selected, and the .value
attribute reflects the object's value. If no value is set either in
HTML or Javascript, the value on
is returned when a radio button
is selected.
Setting a particular radio button is a bit trickier, since you need
to find which radio button should be selected.
Notice that we do not set individual id
attributes in our example,
since that would cause the id
and name
attributes to
not match, which will trigger an error with some HTML checkers. One method
is to group the radio buttons (as in this example) and set the
.checked
property as necessary:
var radios = document.getElementById ('radios'); if (radios) { var inputs = radios.getElementsByTagName ('input'); if (inputs) { for (var i = 0; i < inputs.length; ++i) { if (inputs[i].type == 'radio' && inputs[i].name == 'letter') inputs[i].checked = inputs[i].value == 'two'; } } }
This sample code will select the radio button with value two
.
If you select one radio button in a group, all other buttons in that group
will be deselected.
Selecting a radio button will trigger an onclick
event.
If your event handler returns false, Internet Explorer will not change
the state of any radio buttons. Mozilla will allow the user to select one
radio button, but will prevent any subsequent changes. Safari will, as with
checkboxes, ignore the return value.
While there are many ways different browsers can reflect the selected value, one which works on different browsers is:
var n = obj.selectedIndex; // Which menu item is selected var val = obj[n].text; // Return string value of menu item
To set the value, if you know the correct .selectedIndex
,
you can just set that. If you do not, you need to iterate over the
various values:
for (var i = 0; i < obj.length; ++i) if (obj[i].text == 'Second') obj.selectedIndex = i;
If your HTML also sets value
attributes for the different
menu items, you can read and set the .value
attributes for the
various option objects.
Setting an event handler is trickier than the other form objects, since different browsers trigger different events.
onclick
event for the <select>
.onclick
and then onchange
events for
the <select>
.onchange
event for the <select>
,
an onclick
event for the <option>
which was selected, and then an onclick
event for the <select>
. If the user clicks and releases to activate the menu (instead of clicking and holding), an onclick
event will be generated for the <select>
at that time, too (in other words, just as soon as the mouse is released and before the user actually selects an item).
Below is a small test which will show which events get generated. Each of the <select>
and <option>
tags has onclick
and onchange
events declared so you can see the browser's behavior.
One way to handle the event in a cross-browser manner is to set an
onclick
event handler on the outer select, such as:
<select name="menuchoice" onclick="didselect ()"> <option>First</option> <option>Second</option> <option>Third</option> </select>
You then need to make sure your current object is the same for all browsers:
while (obj && obj.tagName != 'SELECT') obj = obj.parentNode;
All browsers will ignore the return value of the event handler.
If you look at the source for this page, you'll see that the method of retrieving and setting field values is at times quite different than in the examples in the text above. This is to both set up the two form fields (one for changing values, the other for only mirroring those changes) and to only set event handlers where necessary.
The second form on the right is not actually defined in the HTML, but a duplicate of the form on the left is made and inserted into the document using Javascript.
The event handlers are likewise not declared in the HTML, but are assigned at runtime with Javascript. After the window has completed loading, the following happens:
var f = document.getElementById ('firstform'); f.onclick = itemChanged;
The left form has an id
attribute set to firstform
, and
it gets only an onclick
event handler, since we will only use
onchange
event handlers directly on the text field and text area objects.
Those are set with a call to a function which fixes up the master
form:
function fixupMaster (obj) { if (obj.childNodes) for (var i = 0; i < obj.childNodes.length; ++i) { var cobj = obj.childNodes[i]; if ((cobj.tagName == 'INPUT' && cobj.type == 'text') || cobj.tagName == 'TEXTAREA') cobj.onchange = itemChanged; fixupMaster (cobj); } }
While a separate event handler can be used to manage the onchange
events, this page uses the same event handler to demonstrate how one
event handler can manage many different events.
After determining the object which triggered the event, the event handler builds a string which represents the event and triggering object:
var switcher = e.type + '/' + obj.tagName + (obj.tagName == 'INPUT' ? '/' + obj.type : '');
For example, when the event handler is called for an onchange
event from the text area, the string's value is change/TEXTAREA
. An
onclick
event triggered by the checkbox would set the string to
click/INPUT/checkbox
. If there were multiple instances of a
particular item which needed to have different actions (such as
multiple checkboxes), other identifiers could be included in the string.
note that the .type
attribute is only appended if the object
has a .tagName
of INPUT
, since other objects can use
the .type
attribute differently than we would expect.
Once we have this selector string, we can act differently depending on how the event handler was triggered:
switch (switcher) { case 'change/TEXTAREA': case 'change/INPUT/text': // do things for text fields here break; case 'click/INPUT/checkbox': // do things for checkboxes here break; case 'click/INPUT/radio': // do things for radio buttons here break; case 'click/OPTION': while (obj && obj.tagName != 'SELECT') obj = obj.parentNode; case 'click/SELECT': // do things for drop-down menus here break; }
Notice that this event handler looks for the surrounding select object
if an onclick
event is triggered by an option, then falls
through to the handler for the select object. This is functionally
the same as the sample code above for drop-down menus.