Reputation: 63487
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();
}
});
Upvotes: 4
Views: 6013
Reputation: 91
I also found this link very helpful, you should check it out. Here you go: " Live Search a HTML List using jQuery – No Plugin Needed "
Upvotes: 0
Reputation: 140050
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
}
}
Upvotes: 7
Reputation:
I'm not a javascript coder or that familiar with jquery, but I had a similar problem a while ago with a js eye-candy directory tree for a project spec proposal.
The regexp is obviously your bottleneck. Doesn't javascript have efficient array handling functions, instead of the full overhead of a regexp? Isn't the <li>
tag already parsed into the DOM array when the HTML is parsed on document load? It should be simple to walk the DOM tree on those <li>
nodes, copying them into an array, and then use a 'find_value' kind of function on the resulting array to find value.
Upvotes: 0
Reputation: 23803
For starters, I'd use new RegExp
instead of the eval
and see if that improved performance.
I assume you are dynamically populating the li tags. Is there a way to search the data structure from which this list is populated directly instead of searching DOM objects? If my assumption is not right, can you loop through the list in the beginning and build an array of strings which can then later be searched?
Edit: Here's how you can build the list of strings
var listTerms = [];
$("ul#abbreviations li").each(function (li) {
listTerms.push({text : li.firstChild.nodeValue, elem : li});
});
Here's how you can search (simple loop, nothing fancy)
var exp = new RegExp(text, "i");
for(var i=0; i<listTerms.length; i++) {
if (exp.match(listTerms[i].text)) {
$(listTerms[i].elem).hide();
}
}
Upvotes: 2