I am creating a simple listbox filter that takes the user input and returns the matching results in a listbox via javascript/jquery (roughly 5000+ items in listbox). Here is the code snippet:
var Listbox1 = $('#Listbox1');
var mands = document.getElementById('DatabaseCommandsHidden'); //using js for speed
$('#CommandsFilter').bind('keyup', function() {
Listbox1.children().remove();
for (var i = 0; i < mands.options.length; i++) {
if (mands.options[i].text.toLowerCase().match($(this).val().toLowerCase())) {
Listbox1.append($('<option></option>').val(i).html(mands.options[i].text));
}
}
});
This works pretty well, but slows down somewhat when the 1st/2nd char's are being typed since there are so many items.
I thought a solution I could use would be to add a delay to the textbox that prevents the 'keyup' event from being called until the user stops typing. The problem is, I'm not sure how to do that, or if its even a good idea or not.
Any suggestions/help is greatly appreciated.
I am creating a simple listbox filter that takes the user input and returns the matching results in a listbox via javascript/jquery (roughly 5000+ items in listbox). Here is the code snippet:
var Listbox1 = $('#Listbox1');
var mands = document.getElementById('DatabaseCommandsHidden'); //using js for speed
$('#CommandsFilter').bind('keyup', function() {
Listbox1.children().remove();
for (var i = 0; i < mands.options.length; i++) {
if (mands.options[i].text.toLowerCase().match($(this).val().toLowerCase())) {
Listbox1.append($('<option></option>').val(i).html(mands.options[i].text));
}
}
});
This works pretty well, but slows down somewhat when the 1st/2nd char's are being typed since there are so many items.
I thought a solution I could use would be to add a delay to the textbox that prevents the 'keyup' event from being called until the user stops typing. The problem is, I'm not sure how to do that, or if its even a good idea or not.
Any suggestions/help is greatly appreciated.
Share Improve this question asked May 26, 2010 at 13:43 DarcyDarcy 5,36812 gold badges55 silver badges79 bronze badges2 Answers
Reset to default 6You can do a delay like this:
$('#CommandsFilter').keyup(function() {
clearTimeout($.data(this, 'timer'));
var wait = setTimeout(search, 500);
$(this).data('timer', wait);
});
function search() {
var temp = $("<select />");
for (var i = 0; i < mands.options.length; i++) {
if (mands.options[i].text.toLowerCase().match($(this).val().toLowerCase())) {
$('<option></option>', { val: i, html: mands.options[i].text }).appendTo(temp);
}
}
Listbox1.empty().append(temp.children());
}
This stores a timeout on the element you're typing in, if 500ms (adjust as needed) passes between keystrokes, a search executes. Also this appends the elements in a document fragment then into the DOM (still preserving encoding, etc). Depending on the number of items, this may be a decent performance boost as well.
If the mands drop-down isn't changing, I'd suggest the following (note I've dropped jQuery for better performance and patibility). There are several improvements:
- Timer to delay updating the filtered list once half a second has elapsed since the last keypress
- List of mand texts is pre-cached
- Unnecessary use of
match
replaced withindexOf
- Uses fast native DOM manipulation that works in all scriptable browsers since the 1990s
A quick test suggests that for a drop-down with 5000 options containing short strings, it's between 10 and 30 times faster than the jQuery equivalent in most browsers.
Code:
var mands = document.getElementById("DatabaseCommandsHidden");
var filteredDropDown = document.getElementById("Listbox1");
var filterInput = document.getElementById("CommandsFilter");
var timer;
// Create a cached list of the lower case text of the mands drop-down
var mandTexts = [], mandText;
for (var i = 0, len = mands.options.length; i < len; ++i) {
mandText = mands.options[i].text;
mandTexts.push({original: mandText, lower: mandText.toLowerCase()});
}
function populateFilteredDropDown() {
timer = null;
var val = filterInput.value.toLowerCase(), mandText;
var opts = filteredDropDown.options;
filteredDropDown.length = 0;
for (var i = 0, len = mandTexts.length; i < len; ++i) {
mandText = mandTexts[i];
if (mandText.lower.indexOf(val) > -1) {
opts[opts.length] = new Option(mandText.original);
}
}
}
filterInput.onkeyup = function() {
if (timer) {
window.clearTimeout(timer);
}
timer = window.setTimeout(populateFilteredDropDown, 500);
};