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?
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.
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).
Just revisiting an old solution, I thought I'd give it a facelift for it's ~5 year anniversary!
click
event to all header (th
) cells...table
, find all rows (except the first)...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>
If you want to support IE11, you'll need to ditch the ES6 syntax and use alternatives to Array.from
and Element.closest
.
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) }); }) });
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)); } };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With