Java Site MenuProgramming SectionsMiscellaneous StuffConsultancy ServicesDownloadsFeedback Form


JavaScript - Manipulating Drop Downs [Previous] [Home] [Next]


On occasions it is handy to be able to let a user add or remove items from a list on a form. This is fairly easy to do as the options within a <SELECT> list can be manipulated through simple JavaScript.

Consider this table wrapped form definition.

<table cellpadding="10" bgcolor="#ffeecc">
<form method="GET" action="#">
<tr valign="top">
	<td rowspan="2">Options</td>
	<td rowspan="2">
	<select name="list" size="10" style="width:150px">
	</select>
	</td>
	<td>
	<input type="text" name="newtext" size="25" value=""/>
	<input type="button" name="addtext" value="Add" onclick="addText(this.form)"/>
	</td>
</tr>
<tr valign="bottom">
	<td>
	<input type="button" name="delsel" value="Remove" onclick="delSelItem(this.form)"/>
	</td>
</tr>
</form>
</table>

Which renders as below.

Options

Typing into the text box on the right and pressing the Add button will add the text into the select list options array, causing an extra entry to appear in the select list box. If the entered value is already in the select list options then it will not be added again. Selecting an option and pressing the Remove button will remove the selected option from the list.

So how is this done ?

Adding an option

The onclick event function specified for the Add button is called when the button is pressed. The argument, this.form, passes the form object associated with the button to the function. The function then fetches the value of the text box from the form, checks to see if the value is already in the options list and, if not present, adds it in. The function is shown below.

function addText(f){
	var str  = f.elements['newtext'].value;
	var opts = f.elements['list'].options;
	if ( ! inOpts(str,opts) ) {
		opts[opts.length] = new Option(str);
	}
	f.elements['newtext'].value = "";
}

Both the text box and select list are referenced by name in the form's elements array to retrieve their properties, the text value for the text box and the array of options for the select list. Using the associative array access, effectively indexing into a hash table, is the easy way to get hold of a form's input objects, but requires that those elements to be accessed in this way have unique name attribute values.

To check whether the text from the text box is already in the options list, the addtext function makes use of another function, inOpts, which returns true if the given text is already an option, or false if not. The function is shown below.

function inOpts(str,arr){
	for( var i = 0; i < arr.length; i++){
		if ( arr[i].text == str ) return true;
	}
	return false;
}

As arguments, the inOpts function expects the string to check in the options array, and the options array itself. A simple loop over the contents of the array is performed, checking the string against the text property of each element for equality.

If the text from the text box does not appear in the array, it must be added. An object to represent the OPTION form element must be created via a call to its constructor function, and then added to the array. Constructor functions are special in as much as they call into being a object of a given type, with properties set to default values appropriate to the type of the object. In this case the object type is Option. A new object is created using new JavaScript keyword. Some object constructors can take arguments to set properties immediately upon creation of the object. Such is the case with the Object constructor. In this example the text to display and the value of the option is set simultaneously from the same value passed as the sole argument to the constructor.

Once the object is created it is added to the options array at the end using a simple but effective method. The first object in a JavaScript array is element 0, so the value of the length property will always be 1 more than the highest possible index value (an array with 5 elements element will have a length property value of 5, but a maximum index location of 4). So, to add another element at the end of an array it is always possible to assign a value to the index location of the current length of the array.

By adding a new Option object to the options array, the select list automatically redisplays itself with the updated list of options, adding scrollbars as appropriate. As the width of the element has been set to a specific value, any option text that is wider than the element will not be displayed fully.

In this example, once the text box value has been checked and possibly added to the select list, the text box value is set to the empty string in order to provide visual feedback to the user that the operation has completed.

Okay, that deals with adding to the list of options, so how about the deletion of options, how is that done ?

Deleting an option

By pressing the Remove button it's onclick event function, delSelItem, is called. The argument value this.form passes the form object associated with the button to the function, as with the addtext function explained above. The object representing the select list element is fetched from the form elements array by referencing it's name.

As all of the available options for a select list are held in it's options array, the currently selected option must be in that array. The value of the selectedIndex property holds the index location of the currently selected option (the one that is highlighted) in the array. However, if no option has been selected, the value of the selectedIndex property cannot lie within the array bounds (0 to length - 1), and so a value of -1 is used to indicate this.

Once the selected option's index location has been found, a simple check to ensure it is greater than -1 is made to see if an option was indeed selected before the button was pressed. If no option was selected the function returns early. If an option was selected it must be removed from the array. There is a very simple way to do this with the select list options array; assign a null value to the index location. This causes the select list to remove the option from the array for us, and redisplay itself appropriately.

The event function is shown below.

function delSelItem(f){
	var selel = f.elements['list'];
	var idx = selel.selectedIndex;
	if ( idx < 0 )return;
	selel.options[idx] = null;
}

Multiple choice SELECT lists

The functions above work well for single choice select lists, but what about those with the multiple attribute set ? These types of select lists allow for more than one option to be selected at once. This means that the selectedIndex property cannot be used to determine which options must be removed from the options array, as only a single value can be held. the addition of options to the select list does not have to change as the multiple attribute only affects selected options.

Assuming that there are multiple options selected, to be able to delete them this time it is still possible to use the same code, but just press the Remove button multiple times. Each time the button is pressed the first option in the list that is selected will be removed. This is not really satisfactory. Instead it is more desirable to remove all the selected options at the same time.

A simple modification to the delSelItem function can do this. First, let us define a new form, this time with the multiple attribute specified in the <select> element. The onclick event function for the Remove button in this form points to a modified version of the delSelItem function, called delAllItems.

Options

The new function checks the value of the multiple property, which is set to true if the select list has the multiple attribute set. If the value is not true, indicating that only a single option can be selected at once, the same code as before is executed to remove the selected option from the select list. If the value is true new code executes, which starts by getting and holding a reference to the select list options array to use later on. Then it loops around the elements in the array checking the value of the selected property for each one. This is the equivalent of the SELECTED attribute in the OPTION element. When the value is true it means that the associated option has been selected and therefore needs to be removed. Removal is performed in the same way as before, namely assigning a null value to the array index location.

The new function is shown below.

function delAllItems(f){
	var selel = f.elements['list'];
	if ( selel.multiple == true ){
		var opts = selel.options;
		for ( var i = 0; i < opts.length; ){
			if( opts[i].selected == true ){
				opts[i] = null;
			} else {
				i++;
			}
		}
	} else {
		var idx=selel.selectedIndex;
		if( idx < 0 ) return;
		selel.options[idx] = null;
	}
}

Notice how the for loop is controlled. In normal usage a for loop is specified with an initialiser statement that sets up a loop variable, a loop variable test and a post body statement that usually alters the value of the loop variable. In this case there is no post body statement (the expected i++ to point to the next array location is missing), only the initialiser (i = 0) and the loop test (i < opts.length) are present. This is because the loop variable must not be incremented if an option has been removed, as all of the elements following it have actually moved down by one location in the array, and so it is necessary to check the same location index value again. If the next location was checked an option would be missed because of the shifting down. The loop variable is only incremented when an option is not selected.


[Fiendish Home]


Content of this page Copyright © Robert Quince 1996 - 2005.
Site Comments