web-dev-qa-db-fra.com

jQuery table sort

J'ai un tableau HTML très simple avec 4 colonnes:

Facility Name, Phone #, City, Specialty

Je veux que l'utilisateur puisse trier par nom d'installation et par ville uniquement.

Comment puis-je coder cela avec jQuery?

169
tony noriega

Si vous voulez éviter tout ce qu'il vous faut, permettez-moi de vous suggérer: ce simple plug-in sortElements . Usage:

var table = $('table');

$('.sortable th')
    .wrapInner('<span title="sort this column"/>')
    .each(function(){

        var th = $(this),
            thIndex = th.index(),
            inverse = false;

        th.click(function(){

            table.find('td').filter(function(){

                return $(this).index() === thIndex;

            }).sortElements(function(a, b){

                if( $.text([a]) == $.text([b]) )
                    return 0;

                return $.text([a]) > $.text([b]) ?
                    inverse ? -1 : 1
                    : inverse ? 1 : -1;

            }, function(){

                // parentNode is the element we want to move
                return this.parentNode; 

            });

            inverse = !inverse;

        });

    });

Et une démo. (cliquez sur les en-têtes de colonne "ville" et "facilité" pour les trier)

144
James

Je suis tombé sur ça et j'ai pensé y mettre mes 2 centimes. Cliquez sur les en-têtes de colonne pour trier par ordre croissant, puis à nouveau pour trier par ordre décroissant.

  • Fonctionne sous Chrome, Firefox, Opera ET IE (8)
  • Utilise uniquement JQuery
  • Le tri alphabétique et numérique est-il croissant ou décroissant?
$('th').click(function(){
    var table = $(this).parents('table').eq(0)
    var rows = table.find('tr:gt(0)').toArray().sort(comparer($(this).index()))
    this.asc = !this.asc
    if (!this.asc){rows = rows.reverse()}
    for (var i = 0; i < rows.length; i++){table.append(rows[i])}
})
function comparer(index) {
    return function(a, b) {
        var valA = getCellValue(a, index), valB = getCellValue(b, index)
        return $.isNumeric(valA) && $.isNumeric(valB) ? valA - valB : valA.toString().localeCompare(valB)
    }
}
function getCellValue(row, index){ return $(row).children('td').eq(index).text() }
table, th, td {
    border: 1px solid black;
}
th {
    cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
    <tr><th>Country</th><th>Date</th><th>Size</th></tr>
    <tr><td>France</td><td>2001-01-01</td><td>25</td></tr>
    <tr><td><a href=#>spain</a></td><td>2005-05-05</td><td></td></tr>
    <tr><td>Lebanon</td><td>2002-02-02</td><td>-17</td></tr>
    <tr><td>Argentina</td><td>2005-04-04</td><td>100</td></tr>
    <tr><td>USA</td><td></td><td>-6</td></tr>
</table>

** Mise à jour: 2018

164
Nick Grealy

De loin, le plus simple que j'ai utilisé est: http://datatables.net/

Incroyablement simple ... assurez-vous simplement de choisir le chemin de remplacement du DOM (IE, construction d'un tableau et laisser DataTables le reformater), puis assurez-vous de formater votre tableau avec <thead> et <tbody> ou s'il a gagné ' t fonctionne. C'est à peu près le seul casse-tête.

AJAX est également pris en charge, etc. Comme avec tous les très bons morceaux de code, il est également TRÈS facile de tout désactiver. Vous seriez surpris de ce que vous pourriez utiliser, cependant. J'ai commencé avec un DataTable "nu" qui ne triait qu'un seul champ et me rendais compte que certaines fonctionnalités étaient vraiment pertinentes pour ce que je faisais. Les clients adorent les nouvelles fonctionnalités.

Points bonus pour DataTables pour une assistance complète de ThemeRoller ....

J'ai également eu de la chance avec tablesorter, mais ce n'est pas aussi facile, pas aussi bien documenté et il n'a que des fonctionnalités correctes.

39
bpeterson76

Nous venons tout juste de commencer à utiliser cet outil astucieux: https://plugins.jquery.com/tablesorter/

Il existe une vidéo sur son utilisation à l'adresse suivante: http://www.highoncoding.com/Articles/695_Sorting_GridView_Using_JQuery_TableSorter_Plug_in.aspx

    $('#tableRoster').tablesorter({
        headers: {
            0: { sorter: false },
            4: { sorter: false }
        }
    });

Avec une simple table

<table id="tableRoster">
        <thead> 
                  <tr>
                    <th><input type="checkbox" class="rCheckBox" value="all" id="rAll" ></th>
                    <th>User</th>
                    <th>Verified</th>
                    <th>Recently Accessed</th>
                    <th>&nbsp;</th>
                  </tr>
        </thead>
18
Ravi Ram

Ma réponse serait "fais attention". Un grand nombre d’add-ons de tri de table jQuery ne trient que ce que vous transmettez au navigateur. Dans de nombreux cas, vous devez garder à l'esprit que les tableaux sont des ensembles de données dynamiques et peuvent potentiellement contenir des millions de lignes de données.

Vous mentionnez que vous n'avez que 4 colonnes, mais plus important encore, vous ne mentionnez pas le nombre de lignes dont nous parlons ici.

Si vous transmettez 5 000 lignes au navigateur à partir de la base de données, sachant que la table de base de données contient 100 000 lignes, ma question est la suivante: à quoi sert-il de rendre la table triable? Pour effectuer un tri correct, vous devez renvoyer la requête à la base de données et laisser la base de données (un outil conçu pour trier les données) effectue le tri à votre place.

En réponse directe à votre question cependant, le meilleur complément de tri que j'ai rencontré est Ingrid. Il y a de nombreuses raisons pour lesquelles je n'aime pas cet add-on ("cloches et sifflets inutiles ..." comme vous l'appelez), mais l'une des meilleures caractéristiques en termes de tri, c'est qu'il utilise ajax, et ne le fait pas. Ne supposez pas que vous avez déjà passé toutes les données avant de faire le tri.

Je reconnais que cette réponse est probablement excessive (et sur 2 ans de retard) pour vos besoins, mais je suis ennuyé lorsque les développeurs de mon domaine négligent ce point. J'espère donc que quelqu'un d'autre le comprendra.

Je me sens mieux maintenant.

12
cartbeforehorse

J'aime cette réponse acceptée, cependant, vous avez rarement des exigences pour trier le code HTML sans avoir à ajouter d'icônes indiquant la direction du tri. J'ai pris l'exemple d'utilisation de accept answer et corrigé cela rapidement en ajoutant simplement bootstrap à mon projet et en ajoutant le code suivant:

<div></div>

à l'intérieur de chaque <th> afin que vous ayez un emplacement pour définir l'icône.

setIcon(this, inverse);

à partir de l'utilisation de la réponse acceptée, sous la ligne:

th.click(function () {

et en ajoutant la méthode setIcon:

function setIcon(element, inverse) {

        var iconSpan = $(element).find('div');

        if (inverse == false) {
            $(iconSpan).removeClass();
            $(iconSpan).addClass('icon-white icon-arrow-up');
        } else {
            $(iconSpan).removeClass();
            $(iconSpan).addClass('icon-white icon-arrow-down');
        }
        $(element).siblings().find('div').removeClass();
    }

Voici un démo . --Vous devez exécuter la démonstration dans Firefox ou IE ou désactiver la vérification du type MIME de Chrome pour que la démonstration fonctionne. Cela dépend du plugin sortElements, lié par la réponse acceptée, en tant que ressource externe. Juste un heads-up!

6
user534042

C'est une bonne façon de trier une table:

$(document).ready(function () {
                $('th').each(function (col) {
                    $(this).hover(
                            function () {
                                $(this).addClass('focus');
                            },
                            function () {
                                $(this).removeClass('focus');
                            }
                    );
                    $(this).click(function () {
                        if ($(this).is('.asc')) {
                            $(this).removeClass('asc');
                            $(this).addClass('desc selected');
                            sortOrder = -1;
                        } else {
                            $(this).addClass('asc selected');
                            $(this).removeClass('desc');
                            sortOrder = 1;
                        }
                        $(this).siblings().removeClass('asc selected');
                        $(this).siblings().removeClass('desc selected');
                        var arrData = $('table').find('tbody >tr:has(td)').get();
                        arrData.sort(function (a, b) {
                            var val1 = $(a).children('td').eq(col).text().toUpperCase();
                            var val2 = $(b).children('td').eq(col).text().toUpperCase();
                            if ($.isNumeric(val1) && $.isNumeric(val2))
                                return sortOrder == 1 ? val1 - val2 : val2 - val1;
                            else
                                return (val1 < val2) ? -sortOrder : (val1 > val2) ? sortOrder : 0;
                        });
                        $.each(arrData, function (index, row) {
                            $('tbody').append(row);
                        });
                    });
                });
            });
            table, th, td {
            border: 1px solid black;
        }
        th {
            cursor: pointer;
        }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
        <tr><th>id</th><th>name</th><th>age</th></tr>
        <tr><td>1</td><td>Julian</td><td>31</td></tr>
        <tr><td>2</td><td>Bert</td><td>12</td></tr>
        <tr><td>3</td><td>Xavier</td><td>25</td></tr>
        <tr><td>4</td><td>Mindy</td><td>32</td></tr>
        <tr><td>5</td><td>David</td><td>40</td></tr>
    </table>

Le violon peut être trouvé ici:
https://jsfiddle.net/e3s84Luw/

L'explication peut être trouvée ici: https://www.learningjquery.com/2017/03/how-to-sort-html-table-using-jquery-code

5
Julian

Voici un tableau qui peut être utile pour décider lequel utiliser: http://blog.sematext.com/2011/09/19/top-javascript-dynamic-table-libraries/

4
SeanDowney

Celui-ci ne raccroche pas le/les navigateur (s), facile à configurer:

var table = $('table');

$('th.sortable').click(function(){
    var table = $(this).parents('table').eq(0);
    var ths = table.find('tr:gt(0)').toArray().sort(compare($(this).index()));
    this.asc = !this.asc;
    if (!this.asc)
       ths = ths.reverse();
    for (var i = 0; i < ths.length; i++)
       table.append(ths[i]);
});

function compare(idx) {
    return function(a, b) {
       var A = tableCell(a, idx), B = tableCell(b, idx)
       return $.isNumeric(A) && $.isNumeric(B) ? 
          A - B : A.toString().localeCompare(B)
    }
}

function tableCell(tr, index){ 
    return $(tr).children('td').eq(index).text() 
}
2
rapttor

Vous pouvez utiliser un plugin jQuery ( breedjs ) qui fournit un tri, un filtre et une pagination:

HTML:

<table>
  <thead>
    <tr>
      <th sort='name'>Name</th>
      <th>Phone</th>
      <th sort='city'>City</th>
      <th>Speciality</th>
    </tr>
  </thead>
  <tbody>
    <tr b-scope="people" b-loop="person in people">
      <td b-sort="name">{{person.name}}</td>
      <td>{{person.phone}}</td>
      <td b-sort="city">{{person.city}}</td>
      <td>{{person.speciality}}</td>
    </tr>
  </tbody>
</table>

JS:

$(function(){
  var data = {
    people: [
      {name: 'c', phone: 123, city: 'b', speciality: 'a'},
      {name: 'b', phone: 345, city: 'a', speciality: 'c'},
      {name: 'a', phone: 234, city: 'c', speciality: 'b'},
    ]
  };
  breed.run({
    scope: 'people',
    input: data
  });
  $("th[sort]").click(function(){
    breed.sort({
      scope: 'people',
      selector: $(this).attr('sort')
    });
  });
});

Exemple de travail sur le violon

2
João Paulo

Pour répondre à James, je ne changerai que la fonction de tri pour la rendre plus universelle. De cette façon, le texte sera trié par ordre alphabétique et par chiffres.

if( $.text([a]) == $.text([b]) )
    return 0;
if(isNaN($.text([a])) && isNaN($.text([b]))){
    return $.text([a]) > $.text([b]) ? 
       inverse ? -1 : 1
       : inverse ? 1 : -1;
}
else{
    return parseInt($.text([a])) > parseInt($.text([b])) ? 
      inverse ? -1 : 1
      : inverse ? 1 : -1;
}
1
Kaloyan Iliev

La réponse de @Nick Grealy réponse est excellente, mais elle ne prend pas en compte les éventuels attributs rowspan des cellules d'en-tête de la table (et les autres réponses ne le font probablement pas non plus). Voici une amélioration de la réponse de @Nick Grealy qui résout ce problème. Basé sur cette réponse aussi (merci @Andrew Orlov).

J'ai également remplacé la fonction $.isNumeric par un personnalisé (merci @zad) pour le faire fonctionner avec les anciennes versions de jQuery.

Pour l'activer, ajoutez class="sortable" à la balise <table>.

$(document).ready(function() {

    $('table.sortable th').click(function(){
        var table = $(this).parents('table').eq(0);
        var column_index = get_column_index(this);
        var rows = table.find('tbody tr').toArray().sort(comparer(column_index));
        this.asc = !this.asc;
        if (!this.asc){rows = rows.reverse()};
        for (var i = 0; i < rows.length; i++){table.append(rows[i])};
    })

});

function comparer(index) {
    return function(a, b) {
        var valA = getCellValue(a, index), valB = getCellValue(b, index);
        return isNumber(valA) && isNumber(valB) ? valA - valB : valA.localeCompare(valB);
    }
}
function getCellValue(row, index){ return $(row).children('td').eq(index).html() };

function isNumber(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

function get_column_index(element) {
    var clickedEl = $(element);
    var myCol = clickedEl.closest("th").index();
    var myRow = clickedEl.closest("tr").index();
    var rowspans = $("th[rowspan]");
    rowspans.each(function () {
        var rs = $(this);
        var rsIndex = rs.closest("tr").index();
        var rsQuantity = parseInt(rs.attr("rowspan"));
        if (myRow > rsIndex && myRow <= rsIndex + rsQuantity - 1) {
            myCol++;
        }
    });
    // alert('Row: ' + myRow + ', Column: ' + myCol);
    return myCol;
};
1
Dennis Golomazov

J'ai fini par utiliser la réponse de Nick (la plus populaire mais pas acceptée) https://stackoverflow.com/a/19947532/527122

et l'a combiné avec le https://stackoverflow.com/a/16819442/527122 mais n'a pas voulu ajouter d'icônes ou de polices de caractères au projet. Les styles CSS pour sort-colonne-asc/desc j'ai fait la couleur, le remplissage, la bordure arrondie.

Je l'ai également modifié pour qu'il soit classé par classe plutôt que par n'importe quel autre afin que nous puissions contrôler ceux qui sont triables. Cela pourrait également s'avérer utile plus tard s'il y a deux tables, bien que d'autres modifications soient nécessaires pour cela.

corps:

 html += "<thead>\n";
    html += "<th></th>\n";
    html += "<th class=\"sort-header\">Name <span></span></i></th>\n";
    html += "<th class=\"sort-header\">Status <span></span></th>\n";
    html += "<th class=\"sort-header\">Comments <span></span></th>\n";
    html += "<th class=\"sort-header\">Location <span></span></th>\n";
    html += "<th nowrap class=\"sort-header\">Est. return <span></span></th>\n";
    html += "</thead>\n";
    html += "<tbody>\n"; ...

... plus bas dans le corps

$("body").on("click", ".sort-header", function (e) {
    var table = $(this).parents('table').eq(0)
    var rows = table.find('tr:gt(0)').toArray().sort(comparer($(this).index()))
    this.asc = !this.asc
    if (!this.asc) { rows = rows.reverse() }
    for (var i = 0; i < rows.length; i++) { table.append(rows[i]) }

    setIcon(e.target, this.asc);
});

les fonctions:

function comparer(index) {
        return function (a, b) {
            var valA = getCellValue(a, index), valB = getCellValue(b, index)
            return $.isNumeric(valA) && $.isNumeric(valB) ? valA - valB : valA.toString().localeCompare(valB)
        }
    }

    function getCellValue(row, index) {
        return $(row).children('td').eq(index).text()
    }

    function setIcon(element, inverse) {

        var iconSpan = $(element).find('span');

        if (inverse == true) {
            $(iconSpan).removeClass();
            $(iconSpan).addClass('sort-column-asc');
            $(iconSpan)[0].innerHTML = " &#8593 " // arrow up
        } else {
            $(iconSpan).removeClass();
            $(iconSpan).addClass('sort-column-desc');
            $(iconSpan)[0].innerHTML = " &#8595 " // arrow down 
        }

        $(element).siblings().find('span').each(function (i, obj) {
            $(obj).removeClass();
            obj.innerHTML = "";
        });
    }
0
blind Skwirl

Une autre approche pour trier le tableau HTML. (basé sur tri HTML W3.JS)

/* Facility Name */
$('#bioTable th:eq(0)').addClass("control-label pointer");
/* Phone # */
$('#bioTable th:eq(1)').addClass("not-allowed");
/* City */
$('#bioTable th:eq(2)').addClass("control-label pointer");
/* Specialty */
$('#bioTable th:eq(3)').addClass("not-allowed");


var collection = [{
  "FacilityName": "MinION",
  "Phone": "999-8888",
  "City": "France",
  "Specialty": "Genetic Prediction"
}, {
  "FacilityName": "GridION X5",
  "Phone": "999-8812",
  "City": "Singapore",
  "Specialty": "DNA Assembly"
}, {
  "FacilityName": "PromethION",
  "Phone": "929-8888",
  "City": "San Francisco",
  "Specialty": "DNA Testing"
}, {
  "FacilityName": "iSeq 100 System",
  "Phone": "999-8008",
  "City": "Christchurch",
  "Specialty": "gDNA-mRNA sequencing"
}]

$tbody = $("#bioTable").append('<tbody></tbody>');

for (var i = 0; i < collection.length; i++) {
  $tbody = $tbody.append('<tr class="item"><td>' + collection[i]["FacilityName"] + '</td><td>' + collection[i]["Phone"] + '</td><td>' + collection[i]["City"] + '</td><td>' + collection[i]["Specialty"] + '</td></tr>');
}
.control-label:after {
  content: "*";
  color: red;
}

.pointer {
  cursor: pointer;
}

.not-allowed {
  cursor: not-allowed;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.w3schools.com/lib/w3.js"></script>
<link href="https://www.w3schools.com/w3css/4/w3.css" rel="stylesheet" />
<p>Click the <strong>table headers</strong> to sort the table accordingly:</p>

<table id="bioTable" class="w3-table-all">
  <thead>
    <tr>
      <th onclick="w3.sortHTML('#bioTable', '.item', 'td:nth-child(1)')">Facility Name</th>
      <th>Phone #</th>
      <th onclick="w3.sortHTML('#bioTable', '.item', 'td:nth-child(3)')">City</th>
      <th>Specialty</th>
    </tr>
  </thead>
</table>
0
Penny Liu