Sorting HTML table with JavaScript
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
- add a
click
event to all header (th
) cells... - for the current
table
, find all rows (except the first)... - sort the rows, based on the value of the clicked column...
- 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>
Sorting a HTML table with Array#sort
You can use Array.from
to get the td
elements in an array that can be sorted. Then add each of them again to the table in that order. This will be understood as a move in the DOM, so you'll end up with sorted table rows:
let table = document.getElementById("table1");
let trs = table.rows;
Array.from(trs)
.sort((a, b) => a.cells[0].textContent - b.cells[0].textContent)
.forEach(tr => table.appendChild(tr));
<table id="table1">
<tr><td>2</td></tr>
<tr><td>4</td></tr>
<tr><td>3</td></tr>
<tr><td>1</td></tr>
</table>
Sorting a table in JavaScript - hiding table rows with no subsequent rows
This is my Vanilla JavaScript take on it.
Before writing the script I changed all name
attributes to data-name
as tr
s cannot have name
attributes "legally".
In a first filter()
loop I make all tr
s invisible and filter out only those tr
s that don't match the given pattern pat
and are not of class "header". In a forEach()
loop applied on this filtered set I then make only those tr
s visible again that either themselves have a dataset.name
attribute or whose direct successor has this attribute.
const trs=[...document.querySelector("#myTable>tbody").children];
function fltTbl(pat){
trs
.filter(tr=>(tr.style.display="none",tr.classList.contains("header")||
tr.dataset?.name.indexOf(pat)>-1))
.forEach((tr,i,a)=>{
if (tr.dataset.name
|| a[i+1]?.dataset.name)
tr.style.display="";
});
}
<button class="btn" onclick="fltTbl('policy-outcomes')">Policy Outcomes</button>
<button class="btn" onclick="fltTbl('latin_america')">Latin America</button>
<button class="btn" onclick="fltTbl('deforestation')">Deforestation</button>
<table class="mytable" id="myTable">
<tr class="header">
<th style="width:60%;">2020</th>
</tr>
<tr data-name="latin_america_zero-deforestation">
<td>"Cattle Ranchers and Deforestation.”
</td>
</tr>
<tr data-name="latin_america_policy-outcomes">
<td>“Impacts on Land Use Conversion.”
</td>
</tr>
<tr data-name="latin_america_supply-chain_policy-outcomes">
<td>“Costs of the Amazon Soy Moratorium.”
</td>
</tr>
<tr class="header">
<th style="width:60%;">2019</th>
</tr>
<tr data-name="africa_policy-outcomes">
<td>“Environmental Change”
</td>
</tr>
<tr data-name="latin_america_policy-outcomes">
<td>“Land Use Change”
</td>
</tr>
<tr class="header">
<th style="width:60%;">2018</th>
</tr>
<tr data-name="north_america_zero-deforestation">
<td>“Deforestation Remedies”
</td>
</tr>
<tr data-name="latin_america_zero-deforestation">
<td>“Land Use Change in Latin American Cerrados”
</td>
</tr>
</table>
How do I make a custom 'sort by' in HTML Table?
You could code it from scratch using JavaScript or use a plugin like this: https://datatables.net/
Related Topics
When Using Jquery On(), Why Use (Document) VS. the Element Itself
Es6/Es2015 Object Destructuring and Changing Target Variable
Cannot Use Attr with an Object in D3 V4
JavaScript Promises - Reject VS. Throw
Class VS. Static Method in JavaScript
How to Get "Get" Request Parameters in JavaScript
How to Reset (Clear) Form Through JavaScript
JavaScript Variable Definition: Commas VS. Semicolons
How to Change an Element Type Using Jquery
Es6 Object Destructuring Default Parameters
Can JavaScript Access a Filesystem
Chrome 65 Blocks Cross-Origin <A Download>. Client-Side Workaround to Force Download
Why Does JavaScript Variable Declaration at Console Results in "Undefined" Being Printed
$ Variable (Dollar Sign) in Chrome
Need to Find Height of Hidden Div on Page (Set to Display:None)
Is There a Max Number of Arguments JavaScript Functions Can Accept