Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting HTML table with JavaScript

I'm after a table sorting solution (in JavaScript) but I can't seem to find a suitable one yet. I just need it to sort each column alphabetically. It doesn't need to ignore any code or any numbers or to work with currency. Just a click on the column header switches it from sorted a-z/z-a.

Does anyone know of a really simple solution like this?

like image 649
lukeseager Avatar asked Jan 10 '13 21:01

lukeseager


People also ask

Can you sort an HTML table?

Adding the "sortable" class to a <table> element provides support for sorting by column value. Clicking the column headers will sort the table rows by that column's value. Tables must use <thead> and <th> tags for sortable functionality to work. The <th> tag defines a header cell in an HTML table.

How do you sort a table in ascending order in HTML?

Sort Table by Clicking the Headers. Click the headers to sort the table. Click "Name" to sort by names, and "Country" to sort by country. The first time you click, the sorting direction is ascending (A to Z).


1 Answers

Just revisiting an old solution, I thought I'd give it a facelift for it's ~5 year anniversary!

  • Plain Javascript (ES6)
  • Does alpha and numeric sorting - ascending and descending
  • Works in Chrome, Firefox, Safari (and IE11, see below)

Quick explanation

  1. add a click event to all header (th) cells...
  2. for the current table, find all rows (except the first)...
  3. sort the rows, based on the value of the clicked column...
  4. insert the rows back into the table, in the new order.

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></tr>     <tr><td>France</td><td>2001-01-01</td><td><i>25</i></td></tr>     <tr><td><a href=#>spain</a></td><td><i>2005-05-05</i></td><td></td></tr>     <tr><td><b>Lebanon</b></td><td><a href=#>2002-02-02</a></td><td><b>-17</b></td></tr>     <tr><td><i>Argentina</i></td><td>2005-04-04</td><td><a href=#>100</a></td></tr>     <tr><td>USA</td><td></td><td>-6</td></tr> </table>

IE11 Support (non-ES6)

If you want to support IE11, you'll need to ditch the ES6 syntax and use alternatives to Array.from and Element.closest.

i.e.

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.prototype.slice.call(document.querySelectorAll('th')).forEach(function(th) { th.addEventListener('click', function() {         var table = th.parentNode         while(table.tagName.toUpperCase() != 'TABLE') table = table.parentNode;         Array.prototype.slice.call(table.querySelectorAll('tr:nth-child(n+2)'))             .sort(comparer(Array.prototype.slice.call(th.parentNode.children).indexOf(th), this.asc = !this.asc))             .forEach(function(tr) { table.appendChild(tr) });     }) }); 

Comparer function breakdown

For the sake of brevity, I compacted the comparer() function. It's a little complex/hard to read, so here it is again exploded/formatted/commented.

// Returns a function responsible for sorting a specific column index  // (idx = columnIndex, asc = ascending order?). var comparer = function(idx, asc) {       // This is used by the array.sort() function...     return function(a, b) {           // This is a transient function, that is called straight away.          // It allows passing in different order of args, based on          // the ascending/descending order.         return function(v1, v2) {              // sort based on a numeric or localeCompare, based on type...             return (v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2))                  ? v1 - v2                  : v1.toString().localeCompare(v2);         }(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));     } }; 
like image 140
Nick Grealy Avatar answered Sep 19 '22 18:09

Nick Grealy