views:

3269

answers:

7

I have two <select> boxes on a form. Selecting an item in the first <select> box will determine what should appear in the second <select> (Using Ajax http_request).

In some cases there can be a large 500 (guess) items in the second select and it takes time 5-10 seconds to update in IE. Firefox seems to work perfectly.

I wonder if there is a faster way to achieve this. Currently the server creates a string passes it to the client which is then broken up and add each item to the select by creating an option element and then adding it to the <select>.

I did try to create the whole select item as a string on the server and add that to the form but for some reason it wouldn't work in Firefox (missed something?)

Thanks

+2  A: 

Setting it using SelectElement.innerHTML would be the fastest... but that FAILS in IE.

Last I checked, you can do this in IE, if you wrap all the options in a bogus <div> tag, or set the entire .outerHTML of the select list in IE.

scunliffe
A: 

It would help greatly to see your code.

IF you are creating an <option> element and appending it each iteration, you should consider creating all the <option> elements at once, and then appending them all at once.

So (in psuedocode):

// Don't do this:
for choice in choices:
    option = new Options(choice)
    select.append(option)


// Do this instead
var options = array()

for choice in choices:
   options.append( new Options(choice) )

for option in options:
   select.append(option)

// Or you might try building the select element off-screen and then appending to the DOM
var options = array()
var select = new SelectElement()

for choice in choices:
   select.append( new Options(choice) )

dom_element.append(select)
Triptych
how does using the array help? you still need to call {n} appends to the select list (which is what causes the speed issue, since the browser needs to determine after each append if the size of the list needs to be updated)
scunliffe
@scunliffe - browser optimization rarely comes down to Big-O complexity analysis. My guess here was that IE might delay rendering the new Option elements to the screen if they were all attached to the DOM at once, which should speed things up. Just something to try.
Triptych
+1  A: 

I would create the whole select on the server and inject it into the page. That approach bypasses annoying browser discrepancies, and reduces the complexity of the client-side code.

You did mention that you tried that, but it failed in firefox. I would suggest persevering in getting it to work, posting another question asking for help on that issue, or editing your question to show us what you made that didn't work in firefox.

karim79
+1  A: 

500 elements is not a lot, even for IE. You must be doing something else to cause the lag.

I just tried with 500+ options in IE6, IE7, FF2 and FF3 and all were near instantaneous. I used this code:

var data = [
    { text: 'foo', value: 'bar' },
    // ...
    { text: 'foo', value: 'bar' }
];

var select = document.getElementsByTagName('select')[0];
select.options.length = 0; // clear out existing items
for(var i=0; i < data.length; i++) {
    var d = data[i];
    select.options.add(new Option(d.text, i))
}

I would suggest profiling the bit of code that is fetching the data and populating the drop down. Something else might be taking up the time. For example, check that the code that "breaks up" the string value returned from the server is sharp (sounds like you're doing your own custom parsing there).

Crescent Fresh
A: 

When I use the first version of this it works but can be very slow in updating the second select

<html>
<form id='myform' method='post' action='$_SERVER[PHP_SELF]'>
<table>
<tr><td><select onselect='CALL_AJAX_AND_UPDATE();'></select></td></tr>
<tr><td><select id='selectid'></select></td></tr>
</table>
</form>
</html>

<script type=\"text/javascript\">
function UPDATE( updatedata )
{       
    var itemid = document.getElementById('selectid');    

    var data = updatedata.split( '|' );
    var len = data.length;               

    for( i=0; i < len; i ++ )
    {
     var opt = document.createElement('option');
     opt.text = data[i];

     try
     {
      itemid.add( opt, null );      
     }
     catch(ex)
     {
      itemid.add( opt );  
     }  
    }           
}
</script>

This version works in IE, but firefox doesn't seem to post the second selects data. Have I missed something with this.

<html>
<form id='myform' method='post' action='$_SERVER[PHP_SELF]'>
<table>
<tr><td><select onselect='CALL_AJAX_AND_UPDATE();'></select></td></tr>
<tr><td><div id='addselect'></div></td></tr>
</table>
</form>
</html>

<script type=\"text/javascript\">
function UPDATE( updatedata )
{      
    // update data is full select html 
    var itemid = document.getElementById('addselect');    
    itemid.innerHTML = updatedata;               
}
</script>
A: 

I've checked the number of items being added, its about 3000. Can anyone see what I have done wrong in the second example, it works in IE but not Firefox.

+1  A: 

The problem with all these answers with SelectElement.innerHTML is that you cannot do this trick with SELECTs. The solution is to use innerHTML on the PARENT of the SELECT element itself. So in your ajax/jquery/whatever code create a string that contains ALL of the SELECT HTML, and then get the holder (a div or span or whatever) and set the innerHTML to the string you've constructed.

You will need to isolate the SELECT from the page and give it an explicit parent element (span or div) to prevent other html elements from being casualties when you destroy/reconstruct the SELECT element.

Short answer:

parentselectelement.removeChild(selectelement);
parentselectelement.innerHTML = "<select ...><options...></select>";
hova