Tuesday, May 07, 2013

HTML Select element manipulation using Javascript - II


The rest of the 5 points are being discussed below. Check out the previous part here.

6. Remove a single option from the list

Removing single option from a select element is very simple. Check the code below.

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// Delete zeroth option
p.remove(0);
</script>


In the above code, zeroth option item was deleted. And as a result, all the items are moved to 1 place lower than previous position i.e the item at 1st position is now placed at 0th position and so on. The "length" property of the option list also decreased by 1.

Check another example below.





In this case, an item needs to be selected in order to delete it from the drop-down. So, we need to write the following code which will be executed on "click" event of the button.

<script>
function remove_selected_option()
{
  // Get the Select element
  var p = document.getElementById("selectBox");
 
  // Get Selected Item
  var sel = p.options.selectedIndex;
 
  // Delete that item
  p.options.remove( sel );
}
</script>


The above code would run all browsers including IE 7 and 8.

7. Remove all/multiple options from the list

To make a select element look like a list, we need to add a property called "size". If we want to enable multiple selection, we need to include the property "multiple" as shown below.

<select id='selectBox' name='selectBox'  size='10' multiple='multiple'>
 



Now, if we want to delete all options at once, then we can write the following Javascript :

<script>
  // Get the Select element
  var p = document.getElementById("selectBox");

  // Delete All Options
  p.options.length = 0;
</script>


Deleting multiple options would require some complex logic. To delete, we would use the following statement..

elementName.options.remove( OptionIndex );

Now, suppose we want to delete option index 0,1,2,3 and 4. If we simply use a for() loop and start deleting, problem would occur after the first option [0 index] deletion. The options list works quite like an array, hence when one item is deleted, all items are shifted to one position lower. So, the option with index 1 gets shifted to 0th position [index 0] after the 0th option is deleted. Hence if we delete next option with index 1, we would be removing the wrong items because option with previous index 2 is now having index 1.

So, we need to implement some other logic as described below.

i. Loop through all the options, and put all the selected items into an array
ii. Now iterate through that array of selected items, for each item of it, search the select element and remove the matched option.

The above logic is implemented below..

<script>
  // Get the Select element
  var p = document.getElementById("selectBox");

  // Put all selected options into an associative array or object
  var arr = [];
  for( var i=0; i<p.options.length; i++)
  {
    if( p.options[i].selected == true )
    {
      arr[p.options[i].value] = p.options[i].text;
    }
  }
 
  // Now Iterate the Array
  for( var key in arr )
  {
     /// Check each item in select Element
     for( var i=0;i<p.options.length; i++)
     {
        // Matching for both VALUE and TEXT property
    if( p.options[i].value == key && p.options[i].text == arr[key] )
    {
        // Remove the Item
        p.options.remove( i );
          
        // BREAK -- This is IMPORTANT
        // because p.options.length is already decreased by 1
        // as a result of the option deletion
        // But the LOOP does not know this.
        break;
    }

     }

  }

</script>


The above code runs perfectly on all browser including IE7 and IE8.

The "break" statement in the inner loop is absolutely necessary in order to run the code without any error. When any option element is deleted, the length property (p.options.length) would show a value one less than its previous value. But the loop is set to iterate till the old value of this length property. Hence the loop might look for items with indexes fall beyond the existing range. Error would occur in such cases.

8. Edit any option at any position within the list

Editing any existing option within the Options list is very easy. We just create a new option object and assign it to the existing options array as shown in the example below.

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// Create new Option element
var opt = document.createElement("option");

// Set properties
opt.text  = "BMW";
opt.value = "bmw";

// Position of Old Option to be replaced
var i = 3;

// REPLACE it into Options array
p.options[i] =  opt ;
</script>


The above code is quite self-explanatory and it would replace an existing option with new one.

9. Create a copy of the select element and append it to the body

The usage of this would be minimal in web development context, but this would let us learn some more javascript. To achieve this, we would follow the following logic ::

 a. Create second "select" element
 b. Iterate though first "select" element
 c. Copy all options to second "select" element
 d. Append the second "select" element to HTML body

Now check the implementation below ::

<script>

// Get the First Select element
var s = document.getElementById("selectBox");

// Create the second "Select" element
var t = document.createElement("select");

// Iterate through options of first select element
for( var i=0; i<s.options.length; i++)
{
   // Create New Option
   var opt = document.createElement("option");

   // Set Option Properties
   opt.value = s.options[i].value;
   opt.text  = s.options[i].text;

   // Add the new option to 2nd "Select" element
   t.options.add( opt );

   // t.appendChild( opt );  -- WORKS TOO --
}

// Second element is ready
// Now append it to the HTML body
document.body.appendChild(t);

</script>


The above code runs perfectly on Firefox and Chrome. Check the statements ::

t.options.add( opt );  // Adds new Option
t.appendChild( opt );  // Does Same


We have used the first one, while the second one can be used too.

IE causes problems while creating new dynamic options. To get rid of that, we write the above code as shown below ::

<script>

// Get the First Select element
var s = document.getElementById("selectBox");

// Create the second "Select" element
var t = document.createElement("select");

// Iterate through options of first select element
for( var i=0; i<s.options.length; i++)
{
// Create New Option
var opt = new Option( s.options[i].text , s.options[i].value ) ;
  
// Add the new option to 2nd "Select" element
t.options.add( opt );
}

// Second element is ready
// Now append it to the HTML body
document.body.appendChild(t);

</script>


This version runs on all browser smoothly creating a second "select" element.

10. Sorting all options in a Select element

There is no direct method like "sort" to sort all the options in a Select element. However we can follow the following logic to sort a given select element.

a. Copy all the option to another array
b. Sort the array
c. Now iterate the array the recreate options in the Select element.

If the option value and text are same, then we don't have much trouble, the above logic work perfectly. However if they are different, the task becomes heavier. Check out the new logic ::

a. Copy all option value:text combination to an associative array [Object] for future reference
b. Copy all option TEXT to an array.
c. Sort the array
d. Iterate the array
   i. For each value (Option Text) in the array, find a corresponding option VALUE in reference array created in step 1
   ii. For each value, re-create new options in the "Select" element.

Now check the Javascript implementation below.

<script>
// Get the First Select element
var s = document.getElementById("selectBox");

// Iterate through options of first select element
// and create a reference array with option VALUE:TEXT
var opt_reference = [];
var opt_text_arry = [];

// We are not sorting the option "Select a Bike Model"
// Hence, our copying starts from Index 1 below
for( var i=1; i<s.options.length; i++)
{
   // Store Option value and text to reference array
   opt_reference [ s.options[i].value ] = s.options[i].text ;
  
   // Store only the TEXT to the second array for sorting
   opt_text_arry[i-1] = s.options[i].text;
}

// Sort the Array Ascending
opt_text_arry.sort( function(a, b) {
    if(a>b) return 1;
    if(a<b) return -1;
    return 0;
} );


/// Iterate the array and Re-create options
for(i=0; i<opt_text_arry.length; i++ )
{
  var option_text = opt_text_arry[i];
 
  /// FETCH the corresponding option value
  /// against the option text
  var option_val = "";
  for( var key in opt_reference)
  {
     // Option Text matched
     if( opt_reference[key] == option_text )
     {
       option_val = key;
       break;
     }
   
  }

  // Create the new Option
  var opt = new Option( option_text, option_val);
 
  // Put the new option in the Options Array
  // of Select element. We are re-creating
  // new options from index 1 onwards, hence i+1
  // is used in the statement below
  s.options[i+1] = opt;
}
</script>


The above code is quite self-explanatory. This sorts the whole option list leaving the first option "Select a Bike Model" intact. Try it yourself. The code above runs perfectly on all browsers including IE7 and IE8. The pitfalls are in the sort function. If you use the callback function with sort() something like this ::

opt_text_arry.sort( function(a, b) {
    if(a>b)
      return 1;
    else
      return 0;
} );


it is not going to work in IE.

11. Selecting all options in a Select element

This is possible when the select element has multple='multiple' attribute set.
To achieve this, we need to iterate through all the option elements, and add selected = 'selected' to each of them. Check the code below.

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// Loop Through Options
for(var i=0; i<p.options.length; i++) 
{
    var k = p[i];
    // Set the Attribute
    k.setAttribute('selected','selected');
}
</script>

Again, to unselect all the items, we need to do just the opposite, i.e remove the selected='selected' attribute from each of these elements. So, we can change the above loop a little to get the effect. So, this time, instead of using setAttribute(), we are using removeAttribute(). Check the code below.

// Loop Through Options
for(var i=0; 
i<p.options.length; i++)
{
    var k = p[i];
    // Set the Attribute
    k.removeAttribute('selected');
}

However, there is a short-cut to the above method. When we select an element in a SelectBox, its selectedIndex property gets set to the option item's index value. So, if we set it to '-1', it will mean that no options is/are selected. However, for the case of multi-select SelectBox, all the selected option's index values are not stored in this selectedIndex property.

So, if we write the following :: 

// Get the Select element
var p = document.getElementById("selectBox");
// De-Select All options
p.options.selectedIndex = -1;

our target is achieved.

No comments: