hovado
hovado

Reputation: 4958

Live search in html table using cache

I used this code to live search in table:

$search.keyup(function() {
    var value = this.value.toLowerCase().trim();

    $.each($table.find('tbody'), function() {
        if($(this).text().toLowerCase().indexOf(value) == -1)
            $(this).hide();
        else
            $(this).show();
    });
});

It worked great, but now I have 1000+ rows in table and searching is really slow on older machines so I created array from table:

function getTableData() {
    var data = [];
    $table.find('tbody').each(function (rowIndex, r) {
        var cols = [];
        $(this).find('td').each(function (colIndex, c) {
            cols.push(c.textContent);
        });
        data.push(cols);
    });
    return data;
};

And I don't know how to search same way in this array to get tbody index.

Upvotes: 1

Views: 1722

Answers (1)

MartinWebb
MartinWebb

Reputation: 2008

3 Update uses cache and a hidden results box;

Here we hide the table, and create a results list on the fly, please note the html markup is very simple and incorrect but it demonstrates the speed improvements of not touching the dom when we cycle our memory cache, the next improvement would be to cache the html of each row and have it in our cache object, thus no need to get the row from the dom when it matches.

http://jsfiddle.net/hh6aed45/5/

var $search = $('input[type="text"]');
var $table = $('table');
var $result = document.getElementById("search");


var i=1;

function uuid(){
   i++;
   return "A"+i;
};


$search.keyup(function() {
    var value = this.value.toLowerCase().trim(), html="";

    for (row in cache) {
    // the getElementById can be speeded up by caching the html in our memory cache!  
    if (cache[row].indexOf(value) !== -1) html+=document.getElementById(row).innerHTML;
    }
    $result.innerHTML=html;
});



function getTableData() {
    var cache = {};
    $table.find('tbody').each(function (rowIndex, r) {
        $(this).find("tr").each(function(rowIndex,r){
        var cols = [], id = uuid();
        r.id=id;
        $(this).find('td').each(function (colIndex, c) {
        cols.push(c.textContent);
        });
        cache[id]=cols.join(" ").toLowerCase();
    });    
});
return cache;

};

var cache = getTableData();

2 Update uses just a memory cache!

http://jsfiddle.net/hh6aed45/3/

This caches the dom as you requested, I add a uuid as an id so that the search can find each row, i could of cached an object and included a live reference to the dom. in fairness as I said I would only switch on what filters in and switch in the minority, as that would speed the loop as no Dom changes would occur for all rows that are not matching, which out of 10,000 would be many. I would also toggle a css class for "in" and "out", that would allow a live list to be cached of all in items, which then could be hidden before the search starts. So in basic, hide all 10,000 rows, turn on what matches, thus the loop does not touch the Dom unless it has! That is about as fast as you will get it.

var $search = $('input[type="text"]');
var $table = $('table');

var i=1;

function uuid(){
   i++;
   return "A"+i;
};


$search.keyup(function() {
    var value = this.value.toLowerCase().trim();

    for (row in cache) {
        document.getElementById(row).style.display = (cache[row].indexOf(value) === -1) ?     "none" : "table-row";
    }
});



function getTableData() {
    var cache = {};
    $table.find('tbody').each(function (rowIndex, r) {
    $(this).find("tr").each(function(rowIndex,r){
    var cols = [], id = uuid();
    r.id=id;
    $(this).find('td').each(function (colIndex, c) {
        cols.push(c.textContent);
    });
    cache[id]=cols.join(" ").toLowerCase();
    });    
    
    
});
return cache;
};

var cache = getTableData();

1 uses native raw javascript with optimizations;

For this kind of thing plane java-script is a must, if your talking about performance first things first, throw jquery out in your loop. Cache the dom first, dont keep loading it.

Speed is an illusion when your building programs.

For example you could do the lookup after two or three letters, not one. You could also change the code so that if a row does not match it is skipped, not switched into view.

so step one turn all rows on, (find all rows that are off, cache the view as views are live)

step two remove rows, not turn rows on and off as you go, that will speed the loop. here is

a sped up version walking the dom, if we had 10,000 rows two test we could improve and improve.

Here is a starting point, from here we use the steps as suggested above:

var $search = $('input[type="text"]'),
    $table = $('table'),
    $body = $table.find('tbody')
    $rows = $body.find('tr'); // this view of the dom is live!
$search.keyup(function() {
    var value = this.value.toLowerCase().trim();

   //loops are costly, native is ultra fast

   for (var i = 0; l=$rows.length, i < l; i++) {
        $rows[i].style.display= ($rows[i].innerHTML.toLowerCase().indexOf(value) === -1) ?     "none" : "table-row";
   }
 });

http://jsfiddle.net/hh6aed45/

Upvotes: 2

Related Questions