Sindre Sorhus Sindre Sorhus - 5 months ago 13
Javascript Question

Search through a big list fast with jQuery

I'm using this code to search trough about 500 li tags.

$(function() {

$.expr[":"].containsInCaseSensitive = function(el, i, m){
var search = m[3];
if (!search) return false;
return eval("/" + search + "/i").test($(el).text());
};

$('#query').focus().keyup(function(e){
if(this.value.length > 0){
$('ul#abbreviations li').hide();
$('ul#abbreviations li:containsInCaseSensitive(' + this.value + ')').show();
} else {
$('ul#abbreviations li').show();
}
if(e.keyCode == 13) {
$(this).val('');
$('ul#abbreviations li').show();
}
});

});


And here is the HTML:

<input type="text" id="query" value=""/>
<ul id="abbreviations">
<li>ABC<span>description</span></li>
<li>BCA<span>description</span></li>
<li>ADC<span>description</span></li>
</ul>


This script is very slow with this many li tags.

How can I make it faster, and how can I search trough only the ABC text in the li, and not the span tags (without changing the html) ?

I know about the existing plugins, but I need a small implementation like this.




Here's the finished code for anyone interested

var abbrs = {};

$('ul#abbreviations li').each(function(i){
abbrs[this.firstChild.nodeValue] = i;
});

$('#query').focus().keyup(function(e){
if(this.value.length >= 2){
$('ul#abbreviations li').hide();
var filterBy = this.value.toUpperCase();
for (var abbr in abbrs) {
if (abbr.indexOf(filterBy) !== -1) {
var li = abbrs[abbr];
$('ul#abbreviations li:eq('+li+')').show();
}
}
} else {
$('ul#abbreviations li').show();
}
if(e.keyCode == 13) {
$(this).val('');
$('ul#abbreviations li').show();
}
});

Answer

Cache all items into an object first:

var abbrs = {};

$("ul#abbreviations li").each(function (i) {
    abbrs[this.firstChild.nodeValue] = this;
});

Then look for the typed text in your object:

var li = abbrs[this.value.toUpperCase()];
// show li, hide others

Update: For partial matches, you'd have to iterate through the collection:

var filterBy = this.value.toUpperCase();

for (var abbr in abbrs) {
    if (abbr.indexOf(filterBy) !== -1) {
        var li = abbrs[abbr];
        // show li
    }
}