Max Schilling Max Schilling - 6 months ago 100
jQuery Question

Jquery Listbox / Textbox filter

I have the following jquery function for filtering the contents of a listbox on the onkeyup event from a textbox.

function DoListBoxFilter(listBoxSelector, filter, keys, values) {
var list = $(listBoxSelector);
var selectBase = '<option value="{0}">{1}</option>';

list.empty();
for (i = 0; i < values.length; ++i) { //add elements from cache if they match filter

var value = values[i];

if (value == "" || value.toLowerCase().indexOf(filter.toLowerCase()) >= 0) {
var temp = String.format(selectBase, keys[i], value);
list.append(temp);
}
}
}


It works great for small to medium size lists, but it is a little bit slow when working with lists over 300-400 items... Can anyone help with some ideas to optimize the javascript a little bit to speed up the function?

The function is invoked with the following code:

$('#<% = txtSearch.ClientID %>').keyup(function() {

var filter = $(this).val();

DoListBoxFilter('#<% = lstPars.ClientID %>', filter, keys_<% = this.ClientID %>, values_<% = this.ClientID %>);
});


To use this, I bind an asp.net listbox and also populate two javascript arrays (key and value) on the page.

This IS storing the data in two places on the page, but using this method I am able to use the postback of the listbox to get the selected value without using javacript to extract the value and cache it in a hidden div. (it also saves having to run the function at page load on the clients browser.. and that is really the function where I am seeing the slowness, so storing in two places speeds up the page rendering)

I found that I needed to use the javascript array approach because most browsers don't acknowledge any attempts to hide an option tag... only Firefox appears to do it.

I'm not sure its possible to optimize and speed this code up any more, but if anyone has any ideas I would appreciate it.

Thanks,
Max Schilling

Answer

It looks like you might be suffering in terms of performance with large lists because you are appending each item one at a time that matches the filter. I would build up an array of matches (or create a documentFragment) and then append that to the DOM in one go.

function DoListBoxFilter(listBoxSelector, filter, keys, values) {
    var list = $(listBoxSelector);
    var selectBase = '<option value="{0}">{1}</option>';

    list.empty();
    var i = values.length;
    var temp = [];
    var option, value;
    while (i--) {    
        value = values[i];    
        if (value && value.toLowerCase().indexOf(filter.toLowerCase()) !== -1) {
                option = String.format(selectBase, keys[i], value);
                temp.push(option);
        }
    }
    // we got all the options, now append to DOM
    list.append(temp.join(''));  
}