web-dev-qa-db-fra.com

Tri d'un tableau HTML avec JavaScript

Je suis à la recherche d'une solution de tri de table (en JavaScript) mais je n'arrive pas encore à en trouver une qui convient. J'en ai juste besoin pour trier chaque colonne par ordre alphabétique. Il n'est pas nécessaire d'ignorer un code ou des chiffres ou de travailler avec de la monnaie. Un simple clic sur l'en-tête de la colonne permet de changer le tri trié a-z/z-a. 

Est-ce que quelqu'un connaît une solution vraiment simple comme celle-ci?

32
lukeseager

Juste revisiter une ancienne solution , je pensais lui donner un coup de jeune pour son anniversaire de ~ 5 ans!

  • Javascript simple (ES6)
  • Le tri alphabétique et numérique est-il croissant ou décroissant?
  • Fonctionne dans Chrome, Firefox, Safari (et IE11, voir ci-dessous)

Explication rapide

  1. ajoutez un événement click à toutes les cellules d'en-tête (th) ...
    1. pour le table actuel, trouver toutes les lignes (sauf la première) ... 
    2. trier les lignes en fonction de la valeur de la colonne cliquée ...
    3. réinsérez les lignes dans la table, dans le nouvel ordre.

const getCellValue = (tr, idx) => tr.children[idx].innerText || tr.children[idx].textContent;

const comparer = (idx, asc) => (a, b) => ((v1, v2) => 
    v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2)
    )(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));

// do the work...
document.querySelectorAll('th').forEach(th => th.addEventListener('click', (() => {
    const table = th.closest('table');
    Array.from(table.querySelectorAll('tr:nth-child(n+2)'))
        .sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc))
        .forEach(tr => table.appendChild(tr) );
})));
table, th, td {
    border: 1px solid black;
}
th {
    cursor: pointer;
}
<table>
    <tr><th>Country</th><th>Date</th><th>Size</th><th>Cost</th></tr>
    <tr><td>France</td><td>2001-01-01</td><td><i>2,500</i></td><td>$1.23</td></tr>
    <tr><td><a href=#>spain</a></td><td><i>2005-05-05</i></td><td></td><td></td></tr>
    <tr><td><b>Lebanon</b></td><td><a href=#>2002-02-02</a></td><td><b>-17</b></td><td>$0.04</td></tr>
    <tr><td><i>Argentina</i></td><td>2005-04-04</td><td><a href=#>1,000</a></td><td>$3</td></tr>
    <tr><td>USA</td><td></td><td>-6</td><td>$1,238.00</td></tr>
</table>
<i><b>N.B.</b> Currencies are not yet parsed...</i>


Prise en charge d'IE11 (non ES6)

Si vous souhaitez prendre en charge IE11, vous devrez abandonner la syntaxe ES6 et ajouter des polyfill pour Array.from , Array.forEach et Element.closest .

c'est à dire.

var getCellValue = function(tr, idx){ return tr.children[idx].innerText || tr.children[idx].textContent; }

var comparer = function(idx, asc) { return function(a, b) { return function(v1, v2) {
        return v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2);
    }(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));
}};

// do the work...
Array.from(document.querySelectorAll('th')).forEach(function(th) { th.addEventListener('click', function() {
        var table = th.closest('table');
        Array.from(table.querySelectorAll('tr:nth-child(n+2)'))
            .sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc))
            .forEach(function(tr) { table.appendChild(tr) });
    })
});
41
Nick Grealy

J'ai écrit un code qui va trier une table par ligne, en supposant qu'un seul <tbody> et que les cellules n'ont pas de colspan.

function sortTable(table, col, reverse) {
    var tb = table.tBodies[0], // use `<tbody>` to ignore `<thead>` and `<tfoot>` rows
        tr = Array.prototype.slice.call(tb.rows, 0), // put rows into array
        i;
    reverse = -((+reverse) || -1);
    tr = tr.sort(function (a, b) { // sort rows
        return reverse // `-1 *` if want opposite order
            * (a.cells[col].textContent.trim() // using `.textContent.trim()` for test
                .localeCompare(b.cells[col].textContent.trim())
               );
    });
    for(i = 0; i < tr.length; ++i) tb.appendChild(tr[i]); // append each row in order
}
// sortTable(tableNode, columId, false);

Si vous ne voulez pas faire les hypothèses ci-dessus, vous devrez réfléchir à la façon dont vous voulez vous comporter dans chaque situation. (par exemple, mettez tout dans un <tbody> ou additionnez toutes les valeurs précédentes colspan, etc.)

Vous pouvez ensuite l’attacher à chacune de vos tables, par exemple. en supposant que les titres sont en <thead>

function makeSortable(table) {
    var th = table.tHead, i;
    th && (th = th.rows[0]) && (th = th.cells);
    if (th) i = th.length;
    else return; // if no `<thead>` then do nothing
    while (--i >= 0) (function (i) {
        var dir = 1;
        th[i].addEventListener('click', function () {sortTable(table, i, (dir = 1 - dir))});
    }(i));
}

function makeAllSortable(parent) {
    parent = parent || document.body;
    var t = parent.getElementsByTagName('table'), i = t.length;
    while (--i >= 0) makeSortable(t[i]);
}

puis en appelant makeAllSortableonload.


Exemple fiddle de celui-ci travaillant sur une table.

71
Paul S.

Cela fait bien plus que "simplement trier", mais dataTables.net fait ce dont vous avez besoin. Je l'utilise quotidiennement et est bien pris en charge et très rapide (nécessite jQuery)

http://datatables.net/

DataTables est un plug-in pour la bibliothèque Javascript de jQuery. C'est un outil extrêmement flexible, basé sur les bases de l'amélioration progressive, qui ajoutera des contrôles d'interaction avancés à n'importe quel tableau HTML.

Les visualisations Google sont une autre option, mais nécessitent un peu plus de configuration que dataTables, mais ne nécessitent PAS de framework/bibliothèque particulier (autre que google.visualizations): 

http://code.google.com/apis/ajax/playground/?type=visualization#table

Et il existe d'autres options pour ... surtout si vous utilisez l'un des autres frameworks JS. Dojo, Prototype, etc. ont tous des plug-ins "d’amélioration de table" utilisables qui fournissent au minimum une fonctionnalité de tri de table. Beaucoup en fournissent plus, mais je vais reformuler ... Je n'ai pas encore trouvé de système aussi puissant et aussi rapide que datatables.net.

6
BLSully

Le meilleur moyen que je connaisse de trier un tableau HTML avec javascript est avec la fonction suivante.

Il suffit de lui transmettre l'identifiant de la table que vous souhaitez trier et le numéro de colonne sur la ligne. il suppose que la colonne que vous triez est numérique ou contient des chiffres et fera regex remplacer pour obtenir le numéro lui-même (idéal pour les devises et les autres nombres contenant des symboles).

function sortTable(table_id, sortColumn){
    var tableData = document.getElementById(table_id).getElementsByTagName('tbody').item(0);
    var rowData = tableData.getElementsByTagName('tr');            
    for(var i = 0; i < rowData.length - 1; i++){
        for(var j = 0; j < rowData.length - (i + 1); j++){
            if(Number(rowData.item(j).getElementsByTagName('td').item(sortColumn).innerHTML.replace(/[^0-9\.]+/g, "")) < Number(rowData.item(j+1).getElementsByTagName('td').item(sortColumn).innerHTML.replace(/[^0-9\.]+/g, ""))){
                tableData.insertBefore(rowData.item(j+1),rowData.item(j));
            }
        }
    }
}

Exemple:

$(function(){
    // pass the id and the <td> place you want to sort by (td counts from 0)
    sortTable('table_id', 3);
});
5
AfikDeri

Vous pouvez utiliser un tableau JSON et la fonction sort. C'est une structure maintenanable assez facile à manipuler (ex: tri).

Non testé, mais voici l'idée. Cela prendrait en charge les commandes multiples et les commandes séquentielles si vous passez dans un tableau dans lequel vous placez les colonnes dans l'ordre dans lequel elles doivent être classées.

var DATA_TABLE = {
    {name: 'George', lastname: 'Blarr', age:45},
    {name: 'Bob', lastname: 'Arr', age: 20}
    //...
};

function sortDataTable(arrayColNames, asc) { // if not asc, desc
    for (var i=0;i<arrayColNames.length;i++) {
        var columnName = arrayColNames[i];
        DATA_TABLE = DATA_TABLE.sort(function(a,b){
            if (asc) {
                return (a[columnName] > b[columnName]) ? 1 : -1;
            } else {
                return (a[columnName] < b[columnName]) ? 1 : -1;
            }
        });
    }
}

function updateHTMLTable() {
    // update innerHTML / textContent according to DATA_TABLE
    // Note: textContent for firefox, innerHTML for others
}

Maintenant, imaginons que vous ayez besoin de commander par nom de famille, puis par nom et enfin par âge.

var orderAsc = true;
sortDataTable(['lastname', 'name', 'age'], orderAsc);

Cela devrait donner quelque chose comme:

{name: 'Jack', lastname: 'Ahrl', age: 20},
{name: 'Jack', lastname: 'Ahrl', age: 22},
//...
3
Frederik.L

Tri des lignes de tableau par cellule . 1. Un peu plus simple et a quelques fonctionnalités . 2. Distinguez 'numéro' et 'chaîne' lors du tri 3. Ajouter bascule pour trier par ASC, DESC

var index;      // cell index
var toggleBool; // sorting asc, desc 
function sorting(tbody, index){
    this.index = index;
    if(toggleBool){
        toggleBool = false;
    }else{
        toggleBool = true;
    }

    var datas= new Array();
    var tbodyLength = tbody.rows.length;
    for(var i=0; i<tbodyLength; i++){
        datas[i] = tbody.rows[i];
    }

    // sort by cell[index] 
    datas.sort(compareCells);
    for(var i=0; i<tbody.rows.length; i++){
        // rearrange table rows by sorted rows
        tbody.appendChild(datas[i]);
    }   
}

function compareCells(a,b) {
    var aVal = a.cells[index].innerText;
    var bVal = b.cells[index].innerText;

    aVal = aVal.replace(/\,/g, '');
    bVal = bVal.replace(/\,/g, '');

    if(toggleBool){
        var temp = aVal;
        aVal = bVal;
        bVal = temp;
    } 

    if(aVal.match(/^[0-9]+$/) && bVal.match(/^[0-9]+$/)){
        return parseFloat(aVal) - parseFloat(bVal);
    }
    else{
          if (aVal < bVal){
              return -1; 
          }else if (aVal > bVal){
                return 1; 
          }else{
              return 0;       
          }         
    }
}

ci-dessous est un exemple html

            <table summary="Pioneer">

                <thead>
                    <tr>
                        <th scope="col"  onclick="sorting(tbody01, 0)">No.</th>
                        <th scope="col"  onclick="sorting(tbody01, 1)">Name</th>
                        <th scope="col"  onclick="sorting(tbody01, 2)">Belong</th>
                        <th scope="col"  onclick="sorting(tbody01, 3)">Current Networth</th>
                        <th scope="col"  onclick="sorting(tbody01, 4)">BirthDay</th>
                        <th scope="col"  onclick="sorting(tbody01, 5)">Just Number</th>
                    </tr>
                </thead>

                <tbody id="tbody01">
                    <tr>
                        <td>1</td>
                        <td>Gwanshic Yi</td>
                        <td>Gwanshic Home</td>
                        <td>120000</td>
                        <td>1982-03-20</td>
                        <td>124,124,523</td>
                    </tr>
                    <tr>
                        <td>2</td>
                        <td>Steve Jobs</td>
                        <td>Apple</td>
                        <td>19000000000</td>
                        <td>1955-02-24</td>
                        <td>194,523</td>
                    </tr>
                    <tr>
                        <td>3</td>
                        <td>Bill Gates</td>
                        <td>Microsoft</td>
                        <td>84300000000</td>
                        <td>1955-10-28</td>
                        <td>1,524,124,523</td>
                    </tr>
                    <tr>
                        <td>4</td>
                        <td>Larry Page</td>
                        <td>Google</td>
                        <td>39100000000</td>
                        <td>1973-03-26</td>
                        <td>11,124,523</td>
                    </tr>
                </tbody>
            </table>

2
Gwanshic

Voici un exemple complet utilisant du JavaScript pur. L'algorithme utilisé pour le tri est fondamentalement BubbleSort . Voici un Fiddle .

   <!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">

<script type="text/javascript">
    function sort(ascending, columnClassName, tableId) {
        var tbody = document.getElementById(tableId).getElementsByTagName(
                "tbody")[0];
        var rows = tbody.getElementsByTagName("tr");

        var unsorted = true;

        while (unsorted) {
            unsorted = false

            for (var r = 0; r < rows.length - 1; r++) {
                var row = rows[r];
                var nextRow = rows[r + 1];

                var value = row.getElementsByClassName(columnClassName)[0].innerHTML;
                var nextValue = nextRow.getElementsByClassName(columnClassName)[0].innerHTML;

                value = value.replace(',', '.'); // in case a comma is used in float number
                nextValue = nextValue.replace(',', '.');

                if (!isNaN(value)) {
                    value = parseFloat(value);
                    nextValue = parseFloat(nextValue);
                }

                if (ascending ? value > nextValue : value < nextValue) {
                    tbody.insertBefore(nextRow, row);
                    unsorted = true;
                }
            }
        }
    };
</script>
</head>
<body>
    <table id="content-table">
        <thead>
            <tr>
                <th class="id">ID <a
                    href="javascript:sort(true, 'id', 'content-table');">asc</a> <a
                    href="javascript:sort(false, 'id', 'content-table');">des</a>
                </th>
                <th class="country">Country <a
                    href="javascript:sort(true, 'country', 'content-table');">asc</a> <a
                    href="javascript:sort(false, 'country', 'content-table');">des</a>
                </th>
                <th class="some-fact">Some fact <a
                    href="javascript:sort(true, 'some-fact', 'content-table');">asc</a>
                    <a href="javascript:sort(false, 'some-fact', 'content-table');">des</a>
                <th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td class="id">001</td>
                <td class="country">Germany</td>
                <td class="some-fact">16.405</td>
            </tr>
            <tr>
                <td class="id">002</td>
                <td class="country">France</td>
                <td class="some-fact">10.625</td>
            </tr>
            <tr>
                <td class="id">003</td>
                <td class="country">UK</td>
                <td class="some-fact">15.04</td>
            </tr>
            <tr>
                <td class="id">004</td>
                <td class="country">China</td>
                <td class="some-fact">13.536</td>
            </tr>
        </tbody>
    </table>
</body>
</html>

Vous pouvez également consulter la source à partir d'ici: https://github.com/wmentzel/table-sort

2
Willi Mentzel

La réponse acceptée de Nick Grealy est excellente mais agit un peu bizarre si vos lignes se trouvent dans une balise <tbody> (la première ligne n'est pas triée et après le tri, les lignes se retrouvent en dehors de la balise tbody, ce qui risque de perdre le formatage).

Ceci est une solution simple, cependant:

Il suffit de changer:

document.querySelectorAll('th').forEach(th => th.addEventListener('click', (() => {
  const table = th.closest('table');
  Array.from(table.querySelectorAll('tr:nth-child(n+2)'))
    .sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc))
    .forEach(tr => table.appendChild(tr) );

à:

document.querySelectorAll('th').forEach(th => th.addEventListener('click', (() => {
  const table = th.closest('table');
  const tbody = table.querySelector('tbody');
  Array.from(tbody.querySelectorAll('tr'))
    .sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc))
    .forEach(tr => tbody.appendChild(tr) );
0
jedwards

Si votre table ne contient pas ths mais seulement tds (avec en-têtes inclus), vous pouvez essayer les solutions suivantes, basées sur la réponse de Nick Grealy ci-dessus:

const getCellValue = (tr, idx) => tr.children[idx].innerText || tr.children[idx].textContent;

const comparer = (idx, asc) => (a, b) => ((v1, v2) => 
    v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2)
    )(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));

// do the work...
document.querySelectorAll('tr:first-child td').forEach(td => td.addEventListener('click', (() => {
    const table = td.closest('table');
    Array.from(table.querySelectorAll('tr:nth-child(n+2)'))
        .sort(comparer(Array.from(td.parentNode.children).indexOf(td), this.asc = !this.asc))
        .forEach(tr => table.appendChild(tr) );
})));
@charset "UTF-8";
@import url('https://fonts.googleapis.com/css?family=Roboto');

*{
  font-family: 'Roboto', sans-serif;
  text-transform:capitalize;
  overflow:hidden;
  margin: 0 auto;
  text-align:left;
}

table {
	color:#666;
	font-size:12px;
	background:#124;
	border:#ccc 1px solid;
	-moz-border-radius:3px;
	-webkit-border-radius:3px;
	border-radius:3px;
  border-collapse: collapse;
  width: 100%;
}

table td {
	padding:10px;
	border-top: 1px solid #ffffff;
	border-bottom:1px solid #e0e0e0;
	border-left: 1px solid #e0e0e0;
	background: #fafafa;
	background: -webkit-gradient(linear, left top, left bottom, from(#fbfbfb), to(#fafafa));
	background: -moz-linear-gradient(top,  #fbfbfb,  #fafafa);
  width: 6.9in;
}

table tbody tr:first-child td
{
	background: #124!important;
  color:#fff;
}

table tbody tr th
{
  padding:10px;
  border-left: 1px solid #e0e0e0;
	background: #124!important;
  color:#fff;
}
<table>
        <tr><td>Country</td><td>Date</td><td>Size</td></tr>
        <tr><td>France</td><td>2001-01-01</td><td><i>25</i></td></tr>
        <tr><td>spain</td><td>2005-05-05</td><td></td></tr>
        <tr><td>Lebanon</td><td>2002-02-02</td><td><b>-17</b></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>

0
Apolo Radomer

Tri de la colonne de table html au chargement de la page 

var table = $('table#all_items_table');
var rows = table.find('tr:gt(0)').toArray().sort(comparer(3));
for (var i = 0; i < rows.length; i++) {
    table.append(rows[i])
}
function comparer(index) {
    return function (a, b) {
        var v1= getCellValue(a, index),
        v2= getCellValue(b, index);
        return $.isNumeric(v2) && $.isNumeric(v1) ? v2 - v1: v2.localeCompare(v1)
    }
}


function getCellValue(row, index) {
    return parseFloat($(row).children('td').eq(index).html().replace(/,/g,'')); //1234234.45645->1234234
}

 enter image description here

0
Rashid Khitilov

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

var collection = [{
  "Country": "France",
  "Date": "2001-01-01",
  "Size": "25",
}, {
  "Country": "spain",
  "Date": "2005-05-05",
  "Size": "",
}, {
  "Country": "Lebanon",
  "Date": "2002-02-02",
  "Size": "-17",
}, {
  "Country": "Argentina",
  "Date": "2005-04-04",
  "Size": "100",
}, {
  "Country": "USA",
  "Date": "",
  "Size": "-6",
}]

for (var j = 0; j < 3; j++) {
  $("#myTable th:eq(" + j + ")").addClass("control-label clickable");
  $("#myTable th:eq(" + j + ")").attr('onClick', "w3.sortHTML('#myTable', '.item', 'td:nth-child(" + (j + 1) + ")')");
}

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

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

.clickable {
  cursor: pointer;
}
<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="myTable" class="w3-table-all">
  <thead>
    <tr>
      <th>Country</th>
      <th>Date</th>
      <th>Size</th>
    </tr>
  </thead>
</table>

0
Yi-Ting Liu