4umi.com/web/javascript/addoption

Add-an-option

Form Javascript

The standard <select> list allows manipulation of its contained collection of option elements. Long before the createElement() method set a horizon of truly dynamic webpages, the Option() object provided the means to add new members on-the-fly, with the following options:

var obj = new Option( text, value, defaultSelected, selected );

Where:

All parameters are optional, the defaults being empty strings and false booleans.

Once the object has been made, it can be inserted into an existing select list by assigning it to one of its options, overwriting an existing one, or appended to the list by assigning it to the next option after the last one, like this:

var sel = document.forms.myformname.elements.myselectname;
sel.options[ sel.options.length ] = obj;

When this code is run, the item is immediately present on the page. If the list had previously been ‘opened’ or expanded by the user, it is now collapsed to its resting state. As usual, the canvas is not rerendered until the script finishes, so the user will only be able to see it after that.

The example

Choose the last option, labeled ‘Other…’, from any of the three <select> lists below, to trigger the addoption script. The mechanism is the same for all types of lists, as the form shows. The first list is plain and straightforward, the others are attributed with size="7" and the third one also with the multiple="multiple" attribute.

First list
Second list
Third list


Not knowing what to add is no excuse. Try www.kanadas.com/music/composers/B.html or www.barnonedrinks.com/tips/dictionary/c.html, or use random words like alpaca, Brahms and champagne.

The script

In this script, when the variable alphabetical evaluates to false, the new Option is added at index o.length, ie. after the last existing one, which has an index of o.length - 1. The property is immediately updated to reflect the new length. In such scenario, the user added options remain clearly separated from the original ones by the 'other' option.

If alphabetical is true, the new entrees get mixed with the original ones. The existing options are copied to the next position one by one in a quick while loop, starting at the bottom of the list, until the text of an option is alphabetically smaller than the new text and the new addition is inserted. Remove the two calls to toLowerCase and the sorting comparison becomes case sensitive. Numerical sorting would require even other measures, involving some repeated type conversion.

The sel variable determines which option will be selected when the function is finished. If not the new option, the 'other' option which triggered the whole circus remains the chosen one if no other steps are taken.

The order in which to prompt the user for his text and value input, is food for a psychological debate. When such select lists are modified through direct user interferance, in most real applications asking for an invisible value is probably silly.

function addoption( o ) {
 var alphabetical = o.form.elements.alphabox.checked;
 var def = false;
 var sel = o.form.elements.selectbox.checked;
 var val = window.prompt( 'Please enter a value for the new option:', 'example' );
 if( !val ) { return false; }
 var txt = window.prompt( 'Please enter the text to be displayed:', val );
 if( !txt ) { return false; }
 var i = o.length, j;
 if( alphabetical ) {
  while( i-- && ( o[i].text.toLowerCase() > txt.toLowerCase() || i + 1===o.length ) ) {
   j = o[i]; 
   o[i + 1] = new Option( j.text, j.value, j.defaultSelected, j.selected );
  }
  return o[i + 1] = new Option( txt, val, def, sel );
 } else {
  return o[i] = new Option( txt, val, def, sel );
 }
}

function changed() {
 var o = this.options, i = o.length;
 if( this.multiple ) {
  while( i-- ) {
   if( o[i].selected && o[i].value==='other' ) {
    addoption( o ); o[i].selected = false; break;
   }
  }
 } else if( o[this.selectedIndex].value==='other' ) {
  addoption( o );
 }
}

// initialize
(function() {
 var a = document.forms.f.elements, i = a.length;
 while( i-- ) { if( a[i].tagName.toLowerCase()==='select' ) { a[i].onchange = changed; } }
})();

In the end, there can be only one.