home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Previous Section Next Section

8.13 Changing select Element Content

NN 4, IE 4

8.13.1 Problem

You want to change the options in a select element in response to other form control settings.

8.13.2 Solution

Begin by removing all option elements from the desired select element:

document.myForm.mySelect.options.length = 0;

Then repopulate the option elements with new option objects:

document.myForm.mySelect.options[0] = new Option("Extra Fine", "xf", false, false);
document.myForm.mySelect.options[1] = new Option("Fine", "f", false, false);
document.myForm.mySelect.options[2] = new Option("Medium", "m", false, false);

This syntax works for all browsers from IE 4 and NN 4 onward, but Navigator 4 does not resize the width of the select element to fit new, wider option text, and generally requires a call to history.go(0) to force the revised options to appear.

8.13.3 Discussion

The constructor function syntax for the option object is as follows:

var newOpt = new Option("text", "value", isDefaultSelectedFlag, isSelectedFlag);

The text parameter is a string containing the item's label as seen by the user in the select list, while the value parameter is the otherwise hidden string that is submitted with the form if the option is selected. The two Boolean parameters let you set whether the option is the default selected option (i.e., the equivalent of having the selected attribute set in the HTML for the option element), and whether the option is currently selected.

You can replace individual options by assigning a new option object to one of the elements in the options array. But if you need to change multiple items, it's cleaner to remove all of the old ones and start the list fresh.

Data for the new option elements can come from sources such as JavaScript custom objects embedded within the page's script. This means that you have to include all possible data choices within the page's scripts. You'll also have to devise a data structure that works for the kind of data you want to convey via the select element. For example, consider a page that displays two select elements, from which users select the nearest city around the world to which to submit a form. The first select element lists regions of the world. With the choice of each region, the second select element lists the cities belonging only to that region. The HTML for the two select elements is as follows:

Submit Request to: <select name="continent" onchange="setCities(this)">
    <option value="" selected>Choose a Region:</option>
    <option value="africa">Africa</option>
    <option value="asia">Asia</option>
    <option value="australia">Australia/Pacific</option>
    <option value="europe">Europe</option>
    <option value="noamer">North America</option>
    <option value="soamer">South America</option>
</select>&nbsp;
<select name="city">
    <option value="" selected>Choose a City:</option>
</select>

A custom object contains all of the data required for the setCities( ) event handler function to modify the contents of the second select element. Here is the data structure for the data, delivered as a custom JavaScript object:

var regiondb = new Object( )
regiondb["africa"] = [{value:"102", text:"Cairo"},
                      {value:"88", text:"Lagos"},
                      {value:"80", text:"Nairobi"},
                      {value:"55", text:"Pretoria"}];
regiondb["asia"] = [{value:"30", text:"Ankara"},
                    {value:"21", text:"Bangkok"},
                    {value:"49", text:"Beijing"},
                    {value:"76", text:"New Delhi"},
                    {value:"14", text:"Tokyo"}];
regiondb["australia"] = [{value:"64", text:"Suva"},
                          {value:"12", text:"Sydney"}];
regiondb["europe"] = [{value:"11", text:"Athens"},
                      {value:"35", text:"Frankfurt"},
                      {value:"3", text:"London"},
                      {value:"15", text:"Madrid"},
                      {value:"1", text:"Paris"},
                      {value:"10", text:"Rome"},
                      {value:"6", text:"Stockholm"},
                      {value:"97", text:"St. Petersburg"}];
regiondb["noamer"] = [{value:"73", text:"Dallas"},
                      {value:"71", text:"Los Angeles"},
                      {value:"5", text:"New York"},
                      {value:"37", text:"Toronto"}];
regiondb["soamer"] = [{value:"65", text:"Buenos Aires"},
                      {value:"31", text:"Caracas"},
                      {value:"66", text:"Rio di Janeiro"}];

Each time the user makes a new selection from the first select element, the onchange event handler triggers the following function that repopulates the second select element:

function setCities(chooser) {
    var cityChooser = chooser.form.elements["city"];
    // empty previous settings
    cityChooser.options.length = 0;
    // get chosen value to act as index to regiondb hash table
    var choice = chooser.options[chooser.selectedIndex].value;
    var db = regiondb[choice];
    // insert default first item
    cityChooser.options[0] = new Option("Choose a City:", "", true, false);
    if (choice != "") {
        // loop through array of the hash table entry, and populate options
        for (var i = 0; i < db.length; i++) {
            cityChooser.options[i + 1] = new Option(db[i].text, db[i].value);
        }
    }
}

As a data source alternative, if you are using IE 5 and later for Windows or Netscape 6 and later, you can reach out to the server to load XML data into a virtual XML document (see Recipe 14.4), and parse the data in the XML document tree to obtain values for the Option( ) constructor function parameters.

In place of the DOM Level 0 syntax shown thus far, you may instead use the W3C DOM style of node tree modification syntax. You are free to use it for option element modification, but an inconsistency in the implementations between IE (through Version 6) and the W3C DOM (as implemented in NN 6 and later) complicates the matter. The W3C DOM provides two methods of the select element, add( ) and remove( ), that slightly simplify the usual node tree modification sequence for this element. The following function is a W3C DOM version of the setCities( ) function shown earlier. It accounts for the browser differences in the second parameter of the add( ) method:

function setCities(chooser) {
    var newElem;
    var where = (navigator.appName =  = "Microsoft Internet Explorer") ? -1 : null;
    var cityChooser = chooser.form.elements["city"];
    while (cityChooser.options.length) {
        cityChooser.remove(0);
    }
    var choice = chooser.options[chooser.selectedIndex].value;
    var db = regiondb[choice];
    newElem = document.createElement("option");
    newElem.text = "Choose a City:";
    newElem.value = "";
    cityChooser.add(newElem, where);
    if (choice != "") {
        for (var i = 0; i < db.length; i++) {
            newElem = document.createElement("option");
            newElem.text = db[i].text;
            newElem.value = db[i].value;
            cityChooser.add(newElem, where);
        }
    }
}

The second parameter of the add( ) method determines the location of the added option element. The W3C DOM expects either a reference to an existing option element or null. The latter signifies that the added element goes to the end of the list. IE's second parameter is optional, but when supplied, it is supposed to be an integer pointing to the zero-based index of the options array where the added element is to go. If you omit the second parameter or supply a -1, the new option goes to the end of the list. That is the reason for the brief browser sniffing near the beginning of the function to set the second parameter value.

8.13.4 See Also

Recipe 3.8 for creating custom object data structures.

    Previous Section Next Section