I'm writing some JS to sort an HTML table: the HTML table has a header row, clicking on the header of a column sorts the rows according to that column. My general algorithm is as follows:
- Convert HTML into a JavaScript array.
- Sort JavaScript array.
- Reconvert JavaScript array to HTML table.
Right now, my code replaces all of the innerHTML elements of the table. Basically, after it sorts the JS array, it touches every node of the table, rewriting it's innerHTML value. I feel like there might be a more efficient way to do this, but I can't think of it.
EDIT:
Here's the code that does part (3) of the algorithm outlined above. I edited out the irrelevant parts (just some string transformations). The indices are a little weird because I skipped the header row when I converted the table to an array, so I'm pensating for that when rewriting the table.
for (var i = 0; i < numRows-1; i++){
for (var j = 0; j < numCols; j++){
var arrCell = tableArr[i][cols[j]];
tableEl.rows[i+1].cells[j].innerHTML = arrCell;
}
}
I'm writing some JS to sort an HTML table: the HTML table has a header row, clicking on the header of a column sorts the rows according to that column. My general algorithm is as follows:
- Convert HTML into a JavaScript array.
- Sort JavaScript array.
- Reconvert JavaScript array to HTML table.
Right now, my code replaces all of the innerHTML elements of the table. Basically, after it sorts the JS array, it touches every node of the table, rewriting it's innerHTML value. I feel like there might be a more efficient way to do this, but I can't think of it.
EDIT:
Here's the code that does part (3) of the algorithm outlined above. I edited out the irrelevant parts (just some string transformations). The indices are a little weird because I skipped the header row when I converted the table to an array, so I'm pensating for that when rewriting the table.
for (var i = 0; i < numRows-1; i++){
for (var j = 0; j < numCols; j++){
var arrCell = tableArr[i][cols[j]];
tableEl.rows[i+1].cells[j].innerHTML = arrCell;
}
}
Share
Improve this question
edited Oct 30, 2016 at 11:36
Brian Tompsett - 汤莱恩
5,89372 gold badges61 silver badges133 bronze badges
asked Aug 8, 2012 at 14:33
Son of the Wai-PanSon of the Wai-Pan
13.2k16 gold badges48 silver badges56 bronze badges
6
- Do you want to achieve this in pure JS only? – Jeff Noel Commented Aug 8, 2012 at 14:34
- As long as you're generating the new markup in memory and then appending it with only 1 DOM operation, this should be pretty efficient. DOM modifications are far slower than Javascript array operations. – chrisfrancis27 Commented Aug 8, 2012 at 14:38
- @Ghillied Yes. I mean, is there a more efficient way to do this outside of pure JS? Are you suggesting that I turn the header rows into links and re-GET the page from the server with the table sorted? – Son of the Wai-Pan Commented Aug 8, 2012 at 15:03
- @ChrisFrancis For a table of n nodes I'm doing n DOM operations (i.e. I'm rewriting the innerHTML). – Son of the Wai-Pan Commented Aug 8, 2012 at 15:06
- @Avery There isn't a more efficent way to do this other than pure JS. I gave you a way to do it with a library, but using libraries will load additional kilobytes into your page for nothing (since you will not use the other functions inside the library). – Jeff Noel Commented Aug 8, 2012 at 15:07
4 Answers
Reset to default 3Use an array to sort the values and a document fragment to perform the update.
function sortRows(tbody, pare, sortDesc) {
//convert html collection to array
var rows = [].slice.call(tbody.rows);
//sort to desired order
rows.sort(pare);
if (sortDesc) {
rows.reverse();
}
//update table
var fragment = document.createDocumentFragment();
rows.forEach(function (row) {
fragment.appendChild(row);
});
tbody.appendChild(fragment);
}
The plexity will be in the pare function. You will need to take into account the column index and any type conversions and caching you want.
This is a basic example that converts the cell text content to an integer.
function sortTable(table, columnIndex) {
while (table && table.tagName !== 'TABLE') {
table = table.parentNode;
}
if (table) {
sortRows(table.tBodies[0], function pare(topRow, bottomRow) {
var topValue = parseInt(topRow.cells[columnIndex].textContent, 10);
var bottomValue = parseInt(bottomRow.cells[columnIndex].textContent, 10);
return (topValue - bottomValue);
});
}
}
function sortRows(tbody, pare, sortDesc) {
//convert html collection to array
var rows = [].slice.call(tbody.rows);
//sort to desired order
rows.sort(pare);
if (sortDesc) {
rows.reverse();
}
//update table
var fragment = document.createDocumentFragment();
rows.forEach(function (row) {
fragment.appendChild(row);
});
tbody.appendChild(fragment);
}
<table>
<thead>
<tr><th onclick="sortTable(this, 0)">Sort</th><th onclick="sortTable(this, 1)">Sort</th></tr>
</thead>
<tbody>
<tr><td>1</td><td>25</td></tr>
<tr><td>3</td><td>12</td></tr>
<tr><td>2</td><td>40</td></tr>
<tr><td>10</td><td>25</td></tr>
</tbody>
</table>
You could remove the rows from the DOM, do the sort, then add them back onto the DOM.
var tbody = table.tBodies[0];
var placeholder = document.createElement('tbody');
table.replaceChild(placeholder, tbody);
//sort rows in tbody
table.replaceChild(tbody, placeholder);
You can use jQuery and its Datatables plugin. In your datatable statement, you can add
"bSort": true
and the job will be done by the script. Although if you can find a pure JS way I suggest you use it so you don't add useless weight to your web page.
If the data is stored on the server - I would send an Ajax request to the server with the sorting type (ASC, DESC, etc. ), sort the data on the server (using PHP, etc) and then receive the sorted data in JavaScript and write the table pletely new.