Monday, May 13, 2013

HTML Select element manipulation using jQuery - I

We have already discussed select element manipulation with javascript, here we would be solving similar problems using very popular Javascript Framework called jQuery. Using jQuery minimizes the cross-browser conflicts, saves lot of time as we don't have to write long native Javascript statements. jQuery statements are a bit complex, but very compact which means a few lines of jQuery may take the workload of hundred lines of Javascript.

Check the HTML below, it contains the select element which we would be working upon.

<select id='selectBox1' name='select'>
 <option value='apr'> Aprilia </option>
 <option value='duc'> Ducati </option>
 <option value='hro'> Hero </option>
 <option value='hnd'> Honda </option>
 <option value='hyo'> Hyosung </option>
 <option value='kwk'> Kawasaki </option>
 <option value='suz'> Suzuki </option>   
 <option value='yam'> Yamaha </option>
</select>


1. List All options and their values

<!-- LOAD JQUERY LIBRARY -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<script type='text/javascript'>
var j = jQuery.noConflict(); // Avoid Collisions among Libraries

// Define a string
var str="";

// Iterate and Fetch each options and their values
j("#selectBox1 option").each(function(){

  str += j(this).val() + ":" + j(this).text() + "\n";

});

// ALERT
alert(str);
</script>


The code above is much easier to remember and write. j("#selectBox1 option") means we are referring to all option elements contained by the element with ID 'selectBox1'. To access each of the options, we use jQuery each() function which takes a callback function means when jQuery access a single option element it would execute the callback function's contents. val() function returns the option value and text() function returns option text.

To access a paticular option whose value (say, 'suz') is known to us, we can use the following jQuery ...

alert( j("#selectBox1 option[value='suz']").text(); ); 

// Would return " Suzuki "

The equivalent Javascript would be ::

alert( document
.querySelectorAll("#selectBox1 option[value='suz']") .item(0).innerText ) ;

The above statement uses "innerText" would run perfectly on IE8 onwards. To get it run on other browsers, 'innerHTML' or 'textContent' can be used. Because of such browser compatibility issues, developers prefer jQuery to native Javascript.

2. Show selected option's text and value

It is just a one line code..

<script>
alert( j("#selectBox1 option:selected").val() + ":" + j("#selectBox1 option:selected").text() );
</script>

If the select element was a listbox with multiple option selection capability, the we need to give little more effort to get all the selected item's text and value. Check the example below ..

<select id='selectBox1' name='select' multiple='multiple' size='10'>
 <option value='apr'> Aprilia </option>
 <option value='duc'> Ducati </option>
 <option value='hro' selected='selected'> Hero </option>
 <option value='hnd'> Honda </option>
 <option value='hyo'> Hyosung </option>
 <option value='kwk' selected='selected'> Kawasaki </option>
 <option value='suz' selected='selected'> Suzuki </option>   
 <option value='yam'> Yamaha </option>
</select>


Check that " Hero ", " Kawasaki " and " Suzuki " options are selected. Now the jQuery would be like this ::

<script>
// Define a string
var str="";

// Iterate and Fetch each of selected options & their values
j("#selectBox1 option:selected").each(function(){

  str += j(this).val() + ":" + j(this).text() + "\n";

});
// ALERT
alert(str);
</script>


The above code alerts the message as per our expectation... all selected option text and their values are shown.

3. Append new options at the end of the list

A single jQuery statement is sufficient to do this. Check this out..

<script>

j("<option value='bmw'> BMW </option>").appendTo("#selectBox1");

</script>


A new HTML is being referred to when we say j("<option value='bmw'>BMW</option>") which is then appended to the element with ID "selectBox1" using the appendTo() function. We can write the same thing using "append()" function as shown below ..

<script>

j("#selectBox1").append("<option value='bmw'> BMW </option>");

</script>


If the select element does not have any options in the beginning, we can create new options using the above methods. Needless to say that this would work on all browsers including IE7 and IE8.

4. Add a new options at the top of the list

Similarly We can use the "prepend()" and "prependTo()" functions to insert new options at the beginning of the option list.

<script>

// USE prepend() function
j("#selectBox1").prepend("<option value='bmw'> BMW </option>"); 

// USE prependTo() function
j("<option value='bmw'> BMW </option>").prependTo("#selectBox1");

</script>


5. Add new options at any position of the list

Suppose, in a case where we need to insert a new option "BMW" after first option "Aprilia", we can write the following code...

<script>
// Get the option containing "Aprilia"
var t = j("#selectBox1").find("option:contains('Aprilia')");

// Now insert new option after it
j(t).after("<option val='bmw'> BMW </option>");

// Insert the option before it
j(t).before("<option val='bmw'> BMW </option>");
</script>


The node t should be converted to jQuery node by wrapping a j() around it.

Options can be accessed through its index also as we did with Javascript in the other article. It is shown below..

<script>
// This would return Aprilia option's text ( First Child )
var opt = j("#selectBox1 option:nth-child(1)").text(); 
</script>


We use nth-child selector and children indexes start with 1 instead of 0. The first and last child can be accessed using ":first" and ":last" selectors respectively.

<script>
// This would return first option "Aprilia"
var optf = j("#selectBox1 option:first"); 

// This would return last option "Yamaha"
var optl = j("#selectBox1 option:last");  

// Insert a new Node before the first option "Aprilia"
j( optf ). before ("<option value='peu'>Peugeot</option>");

// Insert a new Node after the last option "Yamaha"
j( optl ). after ("<option value='lml'>LML</option>");

// Insert a new node before 2 nodes to last option "Yamaha"
j( optl ). prev() . prev() . before ("<option value='nrt'>Norton</option>");

// Insert a new node 2 nodes down to first option "Aprilia"
j( optf ). next() . next() . before ("<option value='mtt'>MTT</option>");

</script>


All the above codes should run on all browsers. Check the part II of this article here. Check  Implementation in native Javascript of above problems here.

Friday, May 10, 2013

Submit select element with multiple options selected

We have seen select element with multiple options selected in previous arrticle. Here I would discuss what happens when we try to submit  a form with a selectBox having multiple options selected. Check out the form below.

Check the HTML below :

<body>
Which Bike Models you like?
<form name='f' method='POST'>
<table border='0'>
 <tr>
  <td>
    <select id='selectBox1' size='10' multiple='multiple' style='width:100px' name='select'>
    <option value='apr'> Aprilia </option>
    <option value='duc'> Ducati </option>
    <option value='hro'> Hero </option>
    <option value='hnd'> Honda </option>
    <option value='hyo'> Hyosung </option>
    <option value='kwk'> Kawasaki </option>
    <option value='suz'> Suzuki </option>   
    <option value='yam'> Yamaha </option>
    </select>
    <br>
    <input type='submit' value='submit'>
  </td>
 </tr>
</table>
</form>
</body>


Notice that the select element has a name 'select' and the form's method is 'post'. Now when we try to submit this, we get only a single value at the PHP server end. The $_POST/$_REQUEST array would look like this :

Array
(
    [select] => suz
)


Even if we try to change the form's action method to 'GET', situation hardly improves. The URL of the page would be appended with '?select=hnd&select=suz' and $_REQUEST would still get only the last value 'suz' ignoring all other submitted values.

To get rid of this, we just need to use an array-like name for the select element.

<select id='selectBox1' size='10' multiple='multiple' style='width:100px' name='select[]'>

By using this, we would get all selected options in an array form at the PHP's end. Now the $_POST/$_REQUEST would look like this :

Array
(
    [select] => Array
        (
            [0] => hro
            [1] => suz
        )

)


Even if we change the form's action method to 'GET', the URL is appended with '?select[]=hnd&select[]=suz' but the $_REQUEST/$_GET still shows the above structure which proves that it gets all values in an array format. Now it becomes very convenient to run a loop and iterate through the array item and work on them.

Render/Highlight PHP code on browser

To render any PHP file [the code itself] on screen we can use highlight_string() function. Check the following example.

<?php
highlight_string("
 <?php
  \$sal = 10000;
  echo 'Hello';
  echo 'Salary is ' . \$sal;
 ?>
");
?>

 

The function takes a string ( PHP code ) as its argument. It uses the in-built syntax highlighter and adds necessary wrapper tags around PHP keywords and then echoes on screen. The above code renders the following output ::



Notice all the special characters need to be escaped. For example if we use
<?php
highlight_string("
<?php
 $sal = 10000;
?>

");
?>

PHP would look for a variable called $sal during variable expansion  which is not defined earlier. Hence it may generate an error.

We can load a whole PHP file and render the whole code on screen with the highlight_file() function. Check the example below.

<?php
highlight_file("index.php");
?>


And here is the output. It is showing the whole code of "index.php" within "htdocs" folder of my Xampp installation. 




An URL can be passed as argument with the highlight_file() function as shown in the below example.

<?php
highlight_file("http://localhost/index.php");
?>


But you can't see the PHP coding in this case as the PHP file in the URL is first executed and then resultant HTML is shown on screen. This is obvious as otherwise server-side codes can be easily exposed to unauthorized users.

To use http URLs with highlight_file() function, "allow_url_include" must be set to "on" in php.ini configuration file.

However, HTMLs and JavaScripts are not highlighted.

Tuesday, May 07, 2013

IE Error :: IE has stopped working - Fix

This is a very annoying expeience I had recently with IE 9 on Windows 7. And when this error occurs, the messagebox, asking to restart the program or search for a solution, keeps on appearing even if I close the messagebox. When I try to close the messagebox, the page is reloaded and again after some time, the messagebox is shown which asks either to restart the program or search a solution for it on Internet. IE simply becomes unusable as a result.

The followings are the solutions to it. If any one of them does not solve the issue, try all of them.

1. Visit Microsoft Community Site :: Go Here and do as suggested on this Microsoft Community site.

2. Disable Protected Mode :: RUN IE, goto "Tools > Internet Options > Security Tab". Disable the "Enable Protected Mode" checkbox option.

3. Run IE Without Extensions :: From WIn7 start menu, goto "All Programs > Accssories > System Tools > Internet Explorer (No Add-ons)" .. which runs the IE with all the browser extensions disabled. This is done to see if any loaded plugins conflict with IE.

4. Reset IE :: RUN IE, goto goto "Tools > Internet Options > Advanced Tab". At the bottom, there is a "Reset" button, click it to Reset IE.

5. Disable GPU Rendering :: RUN IE, goto goto "Tools > Internet Options > Advanced Tab". Notice the very fist checkbox option saying
   "Use software rendering instead of GPU rendering" ... check it.


I hope the above solutions would definitely help people to get rid of this annoying error on IE.

Copy/Move options from one Select element to another


The above picture tells the problem we are going to solve now. It is two select elements with 4 buttons. The functions of all the buttons are described below.

1. First button moves multiple selected options from left to right select element
2. Second button moves all options from left to right select element
3. Third button moves multiple selected options from right to left select element
4. Fourth button moves all options from right to left select element

We would use the same techniques which were discussed in my previous posts. We would write some functions against the "click" events of those buttons. Now check out the HTML below..

<table border='0'>
 <tr>
  <td>
    <select id='selectBox1' size='10' multiple='multiple' style='width:100px'>
   <option value='apr'> Aprilia </option>
    <option value='duc'> Ducati </option>
    <option value='hro'> Hero </option>
    <option value='hnd'> Honda </option>
    <option value='hyo'> Hyosung </option>
    <option value='kwk'> Kawasaki </option>
    <option value='suz'> Suzuki </option>   
    <option value='yam'> Yamaha </option>

    </select>
  </td>
  <td valign='middle'>
    <!-- FOUR BUTTONS -->
    <input type='button' onclick="move_selected('selectBox1','selectBox2')" value='>' style='width:30px'> <br />
     <input type='button' onclick="move_all('selectBox1','selectBox2')" value='>>' style='width:30px'> <br />
     <input type='button' onclick="move_selected('selectBox2','selectBox1')" value='<' style='width:30px'> <br />
     <input type='button' onclick="move_all('selectBox2','selectBox1')" value='<<' style='width:30px'> <br />

  </td>
  <td>
    <select id='selectBox2' size='10' multiple='multiple' style='width:100px'>
   
    </select>
  </td>
 </tr>
</table>


The select elements are having IDs 'selectBox1' and 'selectBox2'. We call two user-defined functions namely "move_selected" and "move_all". The "move_selected" function takes two parameters, source and target select elements. The second function works with same parameters. We have kept the second select element empty.

Moving selected options from one select element to another would involve following steps ..

a. Copy all selected options from source element to an array
b. Also copy index of items which has been selected and would be deleted after move
c. Next, create options for the target element from the array
d. Delete the moved items from source elements
e. Sort the Target element to keep it neat [Optional]

Moving all items from one to another involves following steps ..

a. Copy all options from source element to target directly
b. Delete the moved items from source elements
c. Sort the Target element to keep it neat [Optional]

Now check out the Javascript functions below which are quite self-explanatory.

<script type="text/javascript">

// Move Selected Items from one to other SelectBox
function move_selected( from, to )
{
  // Get the Select Elements
  var s = document.getElementById(from);
  var t = document.getElementById(to);
 
  // Put the selected elements in an array
  var opt = [];
  var to_be_deleted = [];
  var j = 0;
  var i = 0;
  for( i=0;i<s.options.length;i++)
  { 
    if( s.options[i].selected == true )
    {
      // Copy Value+TEXT for moving
      opt[ s.options[i].value ]  =  s.options[i].text;
     
      // Store the Index, for Deletion
      to_be_deleted[j] = i;
      j++;
    }
  }
 
  // Delete the selected Option from Source select element
  for( i=0;i<to_be_deleted.length;i++)
   s.options.remove( to_be_deleted[i] );
  
  // Iterate thorough all Saved option Value+Text
  // and Insert Into the Target Select element
  for( var key in opt )
  {
    // Create new Option
    var no = new Option( opt[key], key );
   
    // Insert
    t.options[ t.options.length ] = no;
  }
 
  // SORT the Target Select Element
  select_elem_sort(to);
}


// Move ALL Items from one to other SelectBox
function move_all( from, to )
{
  // Get the Select Elements
  var s = document.getElementById(from);
  var t = document.getElementById(to);
 
  // ITERATE Source Element's Option List
  var i = 0;
  for( i=0;i<s.options.length;i++)
  { 
      // Create new Option
      var no = new Option( s.options[i].text, s.options[i].value );
   
      // Insert
      t.options[ t.options.length ] = no;
  }
 
  // Delete All options from source Element
  s.options.length = 0;
 
  // SORT the Target Select Element
  select_elem_sort(to);
}

// This is for sorting the Option List
function select_elem_sort(t)
{
   
    // Get the TARGET Select element
    var s = document.getElementById(t);
   
    // Iterate through its options and create
    // a reference array with option VALUE:TEXT
    var opt_reference = [];
    var opt_text_arry = [];

    // Our copying starts from Index 0
    for( var i=0; 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] = 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;
    } );

    var i=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 0 onwards
      s.options[i] = opt;
    }
}
</script>


The above code runs fine on all browsers including IE7 and IE8. 


You can find some more discussions on HTML Select element here

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.

Monday, May 06, 2013

HTML Select element manipulation using Javascript - I

SelectBox, the HTML <select> element, is an useful thing which we use on various webpages. Here we would be discussing on the following points with select element.

1. List All options and their values
2. Show selected option's text and value
3. Append new options at the end of the list
4. Add new options at the top of the list
5. Add new options at any position of the list
6. Remove a single options from the list
7. Remove all/multiple options from the list
8. Edit any option at any position within the list
9. Create a copy of the select element and append it to the body.
10. Sorting all options in a Select element

11.  Select/UnSelect all options in a Select element

Here we would be solving each point. Here is the select element :

<select id='selectBox' name='selectBox'>
<option value=''   > Select a Bike Model </option>
<option value='suz'> Suzuki </option>
<option value='duc'> Ducati </option>
<option value='hnd'> Honda </option>
<option value='yam'> Yamaha </option>
<option value='kwk'> Kawasaki </option>
<option value='apr'> Aprilia </option>
</select>



1. List All options and their values :

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

// Loop each item
for(i=0; i<p.options.length; i++)
{
  var option = p.options[i].textContent ? p.options[i].textContent : p.options[i].innerText;
  str +=  p.options[i].value + " : " + option + "\n";
}

alert( str );
</script>


The output would be :

 : Select a Bike Model
suz : Suzuki
duc : Ducati
hnd : Honda
yam : Yamaha
kwk : Kawasaki
apr : Aprilia

The first does not have a value specified, hence it is showing nothing in the first row of output. To get the option text, we use textContent for non-IE browser and innerText for IE. Option index starts from 0.

2. Show selected option's text and value

First, we create a function which takes option number as its argument and shows that option on screen. Option list is an array of all the texts starting with index zero.

<script>
var option = getOption ( 2 );

function getOption( option_no )
{
    // Get the Select element
    var p = document.getElementById("selectBox");

    // Declare empty object
    var str = new Object;

    // Try to get that option
    if( p.options[ option_no ] == undefined )
    {
       /// That index is invalid
       /// Hence Empty Object would be returned
    }
    else
    {
      /// Valid Index has been used
      str.option = p.options[option_no].textContent ? p.options[option_no].textContent : p.options[option_no].innerText ;
      str.value  = p.options[option_no].value;

    }

    return str;
}
</script>


The code above is quite self-explanatory. We have also checked whether the passed index is invalid or not. For example, if we call :

var option = getOption( 32 );  /// Out of bound Index

an empty object would be returned to "option" variable. The expression :

p.options[ option_no ] == undefined

checks whether that indexed location exists or not within the options array.


When any option is selected, the 'selectedIndex' property of the select element automatically holds the index number of that item. Hence to get the value and text of the selected item, we need to write the following statements ...

var s = p.options.selectedIndex;
var opt2 = get_option( s );
alert(opt2);

We are simply passing the index of selected option item to the get_option function and the return string ( consisting option text and value ) is collected in variable opt2.

3. Append new options at the end of the list

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

// Create a Dynamic Option called Hyosung
var o = new Option("Hyosung", "hyo");

// Append the new option to the select element
p.appendChild( o );
</script>


We are just creating new option object with the keyword 'new', and the "Option" constructor call takes 2 arguments - Option Text and Option Value. Then we are appending the new option object to SelectBox element. This new option is automatically appended at the end of the list.

The above code may not work in old versions of IE (in IE9 it is okay). In that case we can write the below code which would run in all browsers without any problem.

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

// Create a Dynamic Option called Hyosung
p.options[ p.options.length ] = new Option("Hyosung", "hyo");
</script>

Another function add() would add new options to the list at the last position.

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

// use add() method
p.options.add( new Option('Hyosung', 'hyo') );
<script>


Or we can add new options the following way ... this would run on all browsers including IE 7 and 8.

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

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

// Set properties
opt.text = "Hero";
opt.value = "hro";

// Use add() method to add new options
p.options.add( opt );
</script>



4. Add a new options at the top of the list

We can do it in 2 ways, 1 is long and second is very short. Both the methods are discussed below.

1. In this method, we are going to follow these steps..
   a. Copy all the options of the selectbox to an array
   b. Create a new option object
   c. Insert the new option at the beginning of the array
   d. Remove all options from the selectbox
   e. Insert all options from the array to selectbox element using appendChild() method

Check the code below.

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

// Copy all the options to an array
var str = [];
var i;

// We are ignoring the "Select a Bike Model" option at index 0
for( i=1; i<p.options.length; i++)
{
  str[i] = p.options[i];
}

// Create a Dynamic Option called Hero
var o = new Option("Hero");

// Add value to it
o.setAttribute("value", "hro");

// Insert the new option at the beginning of array
str[0] = o;

// Remove all options from the selectbox
p.options.length = 1;  // "Select a Bike Model" option remain untouched

// Insert all options fom array to Select Box
for( i=0; i<str.length; i++)
{
  p.appendChild( str[i] );
}

</script>


2. This was a long road to achieve what we wanted. Now is the tun for the short-cut route. Check the second method ..
   a. Create a new option object
   b. Find a position where we would be inserting the new option
   c. Insert the new option into the selectbox using insertBefore() method. insertBefore() takes 2 parameters, new node and reference node and as a result, the new node is inserted before the reference node. If reference node is null, the the new node is inserted at the end of the list of options.

Check out the javascipt implementation below.

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

// Create a Dynamic Option called Hero
var o = new Option("Hero");

// Add value to it
o.setAttribute("value", "hro");

// Get the first option, zeroth option is "Select a Bike Model"
var n = p.options[1];

// Insert the new option directly
p.insertBefore( o, n);
</script>


The above methods would not give proper results in older versions of IE. On IE9, they would work perfectly. We can have the following code for getting the proper results in IE7/IE8.

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

// Copy all the options to an array
var str = [];
var i;

// We are ignoring the "Select a Bike Model" option at index 0
for( i=1; i<p.options.length; i++)
{
  str[i] = p.options[i];
}

// Create new Option
str[0] = new Option("Hyosung",'hyo');

// Increase the Option List Count
// Create a placeholder in the select element

p.options.length ++;

// Now copy all option nodes from array to Select element
for( i=1; i<p.options.length; i++)
{
  p.options[i] = str[i-1];
}
</script>


The above code ran well in IE7/IE8. It is quite self-explanatory. We area creating an array and pushing all the options to that array. After that, we create a new Option object and push it to the array. Then we create a new placeholder in the option list of the select element to fit in the new option. Finally we copy all the items of array to the select element's options list. We can use the same method to insert any new Option in the middle position of an option list. Insertion in the middle of such option list is discussed in point 5 below.

Notes :
We can use innerHTML property of select element to insert new options but this would remove all old options.

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

// Overwite everything inside
p.innerHTML = "<option value='1'>1</option> <option value='2'>2</option> <option value='3'>3</option>";
</script>


The above code would insert 3 new options into the select element and erase all old options. However this does not work in IE older versions. The innetHTML method really comes handy when we fetch dynamic options from an ajax call. After we receive the bunch of options as ajax response, we can simple assign it to the innerHTML property of a select element. This is shown below..

<script>
document.getElementById('selectBox').innerHTML = ajaxResponseText;
</script>


5. Add new options at any position of the list

Using insertBefore() method we can insert a new option at any position into a select element. If the second parameter to insertBefore() is null, then the new option is added at the end of the list of options. Check out the code below.

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

// Create a Dynamic Option called Hero
var o = new Option("Hero");

// Add value to it
o.setAttribute("value", "hro");

// Insert "Hero" before "Kawasaki"
// Locate the "Kawasaki" node first

var refer_node = p.options.item(5);

// Now Insert "Hero"
p.insertBefore( o, refer_node );

// Now insert it before "Aprilia"
refer_node = p.options.item( 2 );
p.insertBefore( o, refer_node );

// See THAT the new node o has been moved
// From its previous place (place before Kawasaki)
// to new place (place before Aprilia)


// Remove all Old options
p.options.length = 0;

// Inserts at the end
p.insertBefore(o, null);

/// Multiple Inserts with same node is not possible.
/// A node already inserted, cant be inserted again

p.insertBefore(o, null); // Ineffective
p.insertBefore(o, null); // Ineffective

/// Use cloneNode() to clone a node and insert
var o2 = o.cloneNode();
p.insertBefore(o2, null); // Works
</script>


The above code works in IE9 and other browsers like Firefox and chrome. For IE7/IE8, we can use the method discussed in point 4 above.

Notes ::
1. To Update any old option with new one, we can write the following code :

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

// OverWrite the old Option with new item
p.options[3] = new Option('Option Text', 'Option Value');
</script>


2. To Insert empty elements to the option list, write following code

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

// Insert empty elements at the end
p.options.length = 100;
</script>


The above code increases the option array length to 100 which means if it already has 7 elements in it, 93 more empty options are added to it.

3. We can populate a select element taking values from an javascript object as shown in below example.. This runs on all browsers.

<script>
// Define Object
var obj = { duc:'Ducati', suz:'Suzuki', apr:'Aprilia' };

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

// Iterate Object properties
for(var i in obj)
{
    // Create new Option element
    var opt = document.createElement("option");

    // Set properties
    opt.text  = obj[i];
    opt.value = i;

    // Add it to Options array
    p.options.add( opt );
}
</script>


Check the next part here.

Tuesday, April 30, 2013

Select multiple checkboxes using Javascript and jQuery

Suppose, we have a form as shown below.



It has 3 buttons, when the "Select All" button is clicked, all the checkboxes are checked, while "Select None" button unchecks all the chekboxes. Now, we need to write two javascirpt functions which checks/unchecks all the checkboxes at once. Check out the code below.

<html>
<head>
<script type='text/javascript'>

function fselect_all()
{
 // IE 8 and others support querySelectorAll()
 var col = document.querySelectorAll("input[type=checkbox]");
 for(var i=0; i<col.length; i++ )
 {
   col[i].checked = true; // Check
 }
}

function fselect_none()
{
  // IE 8 and others support querySelectorAll()
 var col = document.querySelectorAll("input[type=checkbox]");
 for(var i=0; i<col.length; i++ )
 {
   col[i].checked = false; // Uncheck
 }
}
</script>
</head>
<body>

<form>
<table>
 <!-- Dynamic Generation of Table Items -->
<?php
  for( $i=1;$i<=10; $i++)
  {
?>
   <tr>
    <td>
      <input type='checkbox' name="sel[<?php echo $i;?>]">
      Item <?php echo $i;?> </td>
   </tr>
<?php 
  }
?> 
 <tr>
  <td>
    <input type='button' value='Select All' onclick='fselect_all()'>
    <input type='button' value='Select None' onclick='fselect_none()'>
    <input type='submit' value='Submit' name='btn_submit'>
  </td>
 </tr>
</table>
</form>
</body>
</html>


Some points to be noticed in the above piece of code ::
1. We are generating the checkboxes using a PHP for loop which generates the following table rows ..

 <tr><td><input type='checkbox' name="sel[1]">  Item 1 </td></tr>
 <tr><td><input type='checkbox' name="sel[2]">  Item 2 </td></tr>

  ...
2. In the fselect_all()  and fselect_none() functions, we are using querySelectoAll() method which is supported in all new browsers. IE8 onwards have support for it. This function takes CSS like selectors for selecting DOM nodes and returns all the matching node/elements as a collection it finds. Then we simply run a Javascript for() loop to iterate each checkbox item and then we set their "checked" property to true or false as needed.

The above task can be easily done using jQuery. Check the new fselect_all() and fselect_none() functions which use jQuery statements for checking/unchecking checkboxes.

function fselect_all()
{
  $("input[type=checkbox]").each(function(){ this.checked = true; });
}

function fselect_none()
{
  $("input[type=checkbox]").each(function(){ $(this).removeAttr('checked'); });
}


The statement " this.checked = true; " is a Javascript one, using the statement $(this).attr('checked',true); instead checks the checkboxes only once. This phenomenon can be seen on jsFiddle. Hence we better use the old Javascript statement for checking all checkboxes.

To add checked='checked' to a Checkbox, we can use jQuery's prop() method. And to remove the check, instead of using removeAttr('checked') we can use removeProp(' checked') method. Adding  checked='checked' using the prop() method may not appear in FireBug etc tools.

Now, we would submit the form and see how the inputs are captured at the server end. Check the PHP code below.

<?php
if( isset($_REQUEST['sel']) )
{
   /// Iterate the Items
   foreach( $_REQUEST['sel'] as $key => $val)
   {
     /// Get the ID
     $customer_id = $key;
    
     /// Do some SQL queries
     ...
   }

}

?>

Only selected items will be captured in the above array at the server side. In the PHP loop above, $val for all the array items would have a value of "on". When a checkbox is checked and submitted, server gets a value of "on" against the element's name unless a value is specified as shown below :

<input type='checkbox' name='sel[]' value='test 1'>