Dynamic Drop-Down Box (Part 1)


How to build a dynamic select box in JavaScript

Part 1 of 3
Suppose, you have an HTML select (dropdown) box with a list of countries and another select box with a list of cities in those countries. You want the second select box to show only those cities that are located in a country selected in the first select box. The best way to achieve it is to use a JavaScript Option object to build options in the second drop-down box dynamically.
We have a list of countries - Canada, USA and France - in the first select box and a list of cities - Toronto, Montreal, Vancouver; Boston, New York, Washington, Houston; Paris, Marseille, Lyon, that will go to the second select box.
First let's build an HTML form with drop-down boxes:
<form name='frm'>
<select name='select1' size=5 onchange='fnSelect()'>
 <option selected>Canada</option>
 <option>USA</option>
 <option>France</option>
</select>

<select name='select2' size=5>
 <option></option>
</select>
</form>
When a user changes a selection in the first drop-down box, a JavaScript function fnSelect() will be activated. Let's write this JavaScript function:
function fnSelect(){
//save the select boxes in variables sel1 and sel2 for convenience.
var sel1 =    document.frm.select1;
var sel2 =  document.frm.select2;

//determine which option has been selected in the first select box
switch(sel1.options.selectedIndex){
 case 0:
  //build a list of options for the first choice
  sel2.options[0] = new Option('Toronto','Toronto');
  sel2.options[1] = new Option('Montreal', 'Montreal');
  sel2.options[2] = new Option('Vancouver', 'Vancouver');
 break;
 case 1:
  //build a list of options for the second choice
  sel2.options[0] = new Option('Boston', 'Boston');
  sel2.options[1] = new Option('New York', 'New York');
  sel2.options[2] = new Option('Washington', 'Washington');
  sel2.options[3] = new Option('Houston', 'Houston');
 break;
 default:
  //build a list of options for the third choice
  sel2.options[0] = new Option('Paris', 'Paris');
  sel2.options[1] = new Option('Marseille', 'Marseille');
  sel2.options[2] = new Option('Lyon', 'Lyon');

}
To force a selection when the web page is loaded, we need to call the JavaScript function on the load event as follows:
window.onload = fnSelect;
Try it here:


Did you see what happened after you selected 'USA' in the first select box and then 'France' ? A city belonging to the USA - Houston - was still in the second select box when we selected 'France' in the first select box. Apparently, we missed something here. What we need now is a piece of code to clear all entries from a select box before adding new ones. Here it is:
var len =sel2.length-1;
for(var i =len; i>=0; i--){
 sel2.remove(i);
}
The HTMLSelectElement has a remove method that removes an element from the collection of OPTION elements for this SELECT. It accepts the index of the item to remove, starting from 0, as a parameter.
When we remove entries from a list we need to start removing them from the bottom and go all the way to the top, otherwise we may miss quite a few entries because the index of entries keeps changing.
What we do here is determine the number of options in a select box - sel2.length - and then remove each option from the select box. Let's put this piece of code into our JavaScript function above:

var len =sel2.length-1;
switch(sel1.options.selectedIndex){
 case 0:
  for(var i =len; i>=0; i--){
   sel2.remove(i);
  }
  //build a list of options for the first choice
  sel2.options[0] = new Option('Toronto','Toronto');
  sel2.options[1] = new Option('Montreal', 'Montreal');
  sel2.options[2] = new Option('Vancouver', 'Vancouver');
  break;
 case 1:
  for(var i =len; i>=0; i--){
   sel2.remove(i);
  }
  //build a list of options for the second choice
  sel2.options[0] = new Option('Boston', 'Boston');
  sel2.options[1] = new Option('New York', 'New York');
  sel2.options[2] = new Option('Washington', 'Washington');
  sel2.options[3] = new Option('Houston', 'Houston');
  break;
 default:
  for(var i =len; i>=0; i--){
   sel2.remove(i);
  }
  //build a list of options for the third choice
  sel2.options[0] = new Option('Paris', 'Paris');
  sel2.options[1] = new Option('Marseille', 'Marseille');
  sel2.options[2] = new Option('Lyon', 'Lyon');

}
Try it here now:

The dynamic selection works as expected now. However, the JavaScript function code is rather lengthy and cannot be easily adapted to include new or different choices. Let's see what we can do to make the JavaScript function more compact.
First of all, we can create arrays out of options for each country, and then loop throught them when a user makes a new selection in the first select box.

var arr1 = new Array('Toronto', 'Montreal', 'Vancouver');
var arr2 = new Array( 'Boston', 'New York', 'Washington', 'Houston');
var arr3 = new Array( 'Paris', 'Marseille', 'Lyon');
var len =sel2.length-1;
 //determine which option has been selected in the first select box
switch(sel1.options.selectedIndex){
 case 0:
  for(var i =len; i>=0; i--){
   sel2.remove(i);
  }
  //build a list of options for the first choice
  for(var i=0; i<arr1.length; i++)
    sel2.options[i] = new Option(arr1[i], arr1[i]);
  break;
 case 1:
  for(var i =len; i>=0; i--){
   sel2.remove(i);
  }
  //build a list of options for the second choice
  for(var i=0; i<arr1.length; i++)
    sel2.options[i] = new Option(arr2[i], arr2[i]);
  break;
 default:
  for(var i =len; i>=0; i--){
   sel2.remove(i);
  }
  //build a list of options for the third choice
  for(var i=0; i<arr1.length; i++)
   sel2.options[i] = new Option(arr3[i], arr3[i]);
}

This is better but there is still a lot of repetitive code. Let's put the code that follows each case in a separate JavaScript function and then call that function on each case selection:

function addItems(sel, arr){
 //clear the existing options
 var len = sel.length-1;
 for(var i =len; i>=0; i--){
  sel2.remove(i);
 }//build new options from an array
 for(var i=0; i<arr.length; i++)
  sel.options[i] = new Option(arr[i], arr[i]);
}

This JavaScript function addItems accepts two parameters: a reference to a select box, and an array that represents new options for the select box. First, it clears options from the select box, and then builds new options from the array that was passed as a second parameter.

The final function will look as follows:

function fnSelect(){

var sel1 =    document.frm.select1;
var sel2 =  document.frm.select2;

switch(sel1.options.selectedIndex){
 case 0:
  addItems(sel2, arr1);
  break;
 case 1:
  addItems(sel2, arr2);
  break;
 default:
  addItems(sel2, arr3);
}

In the next part of the tutorial I will show you how we can make the function flexible enough to allow for any number of options in the first and second select boxes.

No comments:

Post a Comment