Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fastest way to hide thousands of <li> elements?

I have an autocomplete form where the user can type in a term and it hides all <li> elements that do not contain that term.

I originally looped through all <li> with jQuery's each and applied .hide() to the ones that did not contain the term. This was WAY too slow.

I found that a faster way is to loop through all <li> and apply class .hidden to all that need to be hidden, and then at the end of the loop do $('.hidden').hide(). This feels kind of hackish though.

A potentially faster way might be to rewrite the CSS rule for the .hidden class using document.styleSheets. Can anyone think of an even better way?

EDIT: Let me clarify something that I'm not sure too many people know about. If you alter the DOM in each iteration of a loop, and that alteration causes the page to be redrawn, that is going to be MUCH slower than "preparing" all your alterations and applying them all at once when the loop is finished.

like image 325
Nick Avatar asked Aug 12 '12 19:08

Nick


People also ask

What will be the jquery code to hide all even elements in a Li element?

Description. "$("li:hidden")" Selects all elements matched by <li> that are hidden.

What property is needed to hide elements?

The visibility property is used to hide or show the content of HTML elements. The visibility property specifies that the element is currently visible on the page. The 'hidden' value can be used to hide the element. This hides the element but does not remove the space taken by the element, unlike the display property.

How do you hide an element in an array?

Each <li> is placed inside a <span> for the purpose of handling any clicks and toggling the item to be visible or hidden. Clicking on each list item (which is populated from your sender array) will hide that item if it's currently visible, or show it if it's currently hidden.

How do you hide an element without space?

The following style rule hides an element on a web page: display: none; When you set the value of display to none, the affected element will disappear. This means the element will no longer take up any space on the web page.


1 Answers

Whenever you're dealing with thousands of items, DOM manipulation will be slow. It's usually not a good idea to loop through many DOM elements and manipulate each element based on that element's characteristics, since that involves numerous calls to DOM methods in each iteration. As you've seen, it's really slow.

A much better approach is to keep your data separate from the DOM. Searching through an array of JS strings is several orders of magnitude faster.

This might mean loading your dataset as a JSON object. If that's not an option, you could loop through the <li>s once (on page load), and copy the data into an array.

Now that your dataset isn't dependent on DOM elements being present, you can simply replace the entire contents of the <ul> using .html() each time the user types. (This is much faster than JS DOM manipulation because the browser can optimize the DOM changes when you simply change the innerHTML.)

var dataset = ['term 1', 'term 2', 'something else', ... ];

$('input').keyup(function() {
    var i, o = '', q = $(this).val();
    for (i = 0; i < dataset.length; i++) {
        if (dataset[i].indexOf(q) >= 0) o+='<li>' + dataset[i] + '</li>';
    }
    $('ul').html(o);
});

As you can see, this is extremely fast.


Note, however, that if you up it to 10,000 items, performance begins to suffer on the first few keystrokes. This is more related to the number of results being inserted into the DOM than the raw number of items being searched. (As you type more, and there are fewer results to display, performance is fine – even though it's still searching through all 10,000 items.)

To avoid this, I'd consider capping the number of results displayed to a reasonable number. (1,000 seems as good as any.) This is autocomplete; no one is really looking through all the results – they'll continue typing until the resultset is manageable for a human.

like image 187
josh3736 Avatar answered Sep 30 '22 23:09

josh3736