web-dev-qa-db-fra.com

Trier une table rapidement par sa première colonne avec Javascript ou jQuery

J'ai un tableau qui est rempli dynamiquement de FullCalendar. Le problème est que FullCalendar ne se soucie pas de son ordre d'origine.

Le tableau ressemble à ceci:

<table id="caltbl">
   <thead>
       <tr> <th> </th>   <th> Date </th>   <th> hours </th>  ... </tr>
   </thead>
   <tbody>
       <tr> <td class="sortnr">1</td>   <td></td> ... </tr>
       <tr> <td class="sortnr">3</td>   <td></td> ... </tr>
       <tr> <td class="sortnr">2</td>   <td></td> ... </tr>
       <tr> <td class="sortnr">4</td>   <td></td> ... </tr>
   </tbody>
</table>

La première de chaque ligne contient le numéro sur lequel la table doit être triée.

J'ai eu ce code pour le trier:

    var rows = $('#caltbl > tbody').children('tr').detach();

    for (var counter = 1; counter<=rows.length; counter++) {
        $(rows).each(function(index) {
            if ($(this).find(".sortnr").text()==counter){
               $('#caltbl > tbody:last').append($(this));
            }
        });
    }

Cela fonctionne bien dans Firefox mais me cause un mal de tête majeur dans Internet Explorer car il y a plus de 500 éléments et il se bloque. Je pourrais ajouter un setTimeout mais cela ne résoudrait pas le vrai problème. Le tri est lent. Quel est un moyen plus rapide de trier cela?

Au lieu d'avoir à partir du <table> html, comme je l'ai dit, il est rempli dynamiquement, donc j'ai une Array qui contient le code HTML. 1 article par <tr> (non trié)

23
Stefanvds

Fiddle: http://jsfiddle.net/qNwDe/

J'ai écrit une méthode efficace, multi-navigateur, pour trier les lignes de votre table. Plusieurs sélecteurs JQuery dans des boucles doubles posent de graves problèmes de performances (comme vous l'avez remarqué), c'est pourquoi je me suis débarrassé de JQuery.

Un autre avantage de ma fonction est que les numéros d’index manquants ne me dérangent pas. Je parle actuellement de la première cellule de chaque ligne, plutôt que d'obtenir l'élément par nom de classe. Si vous voulez vous référer par nom de classe, je modifierai ma fonction:

function sortTable(){
    var tbl = document.getElementById("caltbl").tBodies[0];
    var store = [];
    for(var i=0, len=tbl.rows.length; i<len; i++){
        var row = tbl.rows[i];
        var sortnr = parseFloat(row.cells[0].textContent || row.cells[0].innerText);
        if(!isNaN(sortnr)) store.Push([sortnr, row]);
    }
    store.sort(function(x,y){
        return x[0] - y[0];
    });
    for(var i=0, len=store.length; i<len; i++){
        tbl.appendChild(store[i][1]);
    }
    store = null;
}

Appelez sortTable() chaque fois que vous souhaitez trier la table.

50
Rob W

Essayez une approche comme celle-ci: http://jsfiddle.net/qh6JE/

var rows = $('#caltbl > tbody').children('tr').get(); // creates a JS array of DOM elements
rows.sort(function(a, b) {  // use a custom sort function
    var anum = parseInt($(a).find(".sortnr").text(), 10);
    var bnum = parseInt($(b).find(".sortnr").text(), 10);
    return anum-bnum;
});
for (var i = 0; i < rows.length; i++) {  // .append() will move them for you
    $('#caltbl > tbody').append(rows[i]);
}
7
Blazemonger

Je pense qu'il y a beaucoup trop de boucles dans votre cas. Avec 500 éléments, vous bouclez 500 * 500 = 250000 fois. Peu de navigateurs savent comment faire cela.

Je suggère d'utiliser la méthode native array.sort() de javascript pour effectuer le tri en fonction d'une "fonction de comparaison" personnalisée.

Voici comment cela pourrait être fait (et probablement optimisé): http://jsfiddle.net/tsimbalar/Dw6QE/ .

L'idée est de trier une liste de lignes comparant la valeur sortNumber ... 

5
tsimbalar

Découvrez ceci http://square.github.com/crossfilter/ l'équipe de Square a utilisé une technique d'index bitmap intelligente pour permettre de filtrer des données de 5,3 Mo en <30ms ... mais c'est une technique très intéressante

1
Deano

Nous pouvons utiliser jquery au lieu de javascript pour la même réponse de Rob W. Cela n'affectera aucun problème de performances tel que les sélecteurs multiples JQuery en double boucle.

var $tbody = $('table tbody');
            $tbody.find('tr').sort(function (a, b) {
                var tda = $(a).find('td:eq(' + ColumnIndex + ')').text(); // Use your wished column index
                var tdb = $(b).find('td:eq(' + ColumnIndex + ')').text(); // Use your wished column index
                // if a < b return 1
                return tda > tdb ? 1
                       // else if a > b return -1
                       : tda < tdb ? -1
                       // else they are equal - return 0    
                       : 0;
            }).appendTo($tbody);

Utilisez <au lieu de> pour descendre.

VIOLON

1
SharmaPattar