I have adapted the following code from a tutorial to filter li elements based upon their contents:
$('#_selectSearch_' + index).keyup(function() {
var filter = $(this).val();
if(filter) {
$('#_selectDrop_' + index).find("li:not(:contains(" + filter + "))").slideUp();
$('#_selectDrop_' + index).find("li:contains(" + filter + ")").slideDown();
} else {
$('#_selectDrop_' + index).find("li").slideDown();
}
});
The code works just fine but when working with large lists is very slow bringing the browser to a grinding halt for seconds with every key-press. I have been looking around and have come to the conclusion that the way to improve this is to somehow cache the list and not operate directly on the DOM but have no idea how to implement this.
If your main concern is performance the following code:
- caches element containing filter string.
- caches li elements.
- doesn't show or hide elements that are already in that state.
- uses indexOf which is very fast.
- if the user types letters under 500 milliseconds apart the showMatches will not run.
var selectSearch = $("#_selectSearch_" + index );
var li = $("#_selectDrop_" + index + " li");
var currentTimeout;
selectSearch.on( "keyup", function( ) {
if( currentTimeout ) { window.clearTimeout( currentTimeout ) };
currentTimeout = setTimeout( showMatches, 500 );
});
function showMatches( ) {
var txt = selectSearch.val();
for( var i = 0, len = li.length; i < len; i++ ) {
var content = li[i].textContent ? li[i].textContent : li[i].innerText;
if( txt && content.indexOf( txt ) > -1) {
if( li[i].style.display !== "block" ) {
li[i].style.display = "block";
}
} else {
if( li[i].style.display !== "none" ) {
li[i].style.display = "none";
}
}
}
}
Fiddle with 400 li elements here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With