Reputation: 704
Yes, I know there are a lot of JS/jQuery programs out there to do this. I'm currently using http://www.kryogenix.org/code/browser/sorttable/sorttable.js . It's very easy: just a JS file, add a few class attributes to your table, and you're off. In particular, you don't actually need to know JS to use it, and you can add custom sort keys without needing to write your own JS to extend it. I like it a lot for those two reasons. The main problem: my table is ~9300 rows long, and sorting takes 10-20 seconds. So I'm wondering, are any other scripts out there faster than this? These are the ones I've found:
http://webfx.eae.net/dhtml/sortabletable/sortabletable.html (Not even sure what this uses)
http://tablesorter.com/docs/ (Really really nice, but not easy to extend, requires knowing JS/jQuery)
http://flexigrid.info/ (Overkill, I just need a table sorter, not a whole data manipulation program)
http://datatables.net/ (Overkill, requires Js/jQuery to extend)
I'm sure there's 5000 other programs that can do what I want, but I don't have the time to figure out and test them all to see if they're fast. Thus I'd like to know if someone out there on StackOverflow can point me to whichever library they know to be fast, so I only have to figure out how to use one program.
(Btw, I've seen Java sort hundreds of thousands of numbers in milliseconds with quicksort; does anyone know what algorithm JS.sort() uses?)
Upvotes: 9
Views: 14567
Reputation: 358
I know this post is a bit old, but here's the ES6+ solution that worked pretty great for me.
/**
* Sort table data based on a direction of asc or desc for a specific column
* @param {number} n- column number calling this sort
* @param {string} dir -direction of the sort (asc or desc)
* @param {HTMLSpanElement} targetElem -sort icon
*/
function sortTable(n, dir = "asc", targetElem) {
targetElem.style.cursor = "progress";
let sortArr = [];
let table =targetElem.closest('table');
table.querySelectorAll('tbody > tr > td:nth-Child(' + parseInt(n) + ')').forEach((x, y) => sortArr.push(
{
sortText: x.innerHTML.toLowerCase(),
rowElement: x.closest('tr')
}));
var sorted = sortArr.sort(function (a, b) {
if (dir == "asc") {
if (a.sortText < b.sortText) {
return -1;
}
} else if (dir == "desc") {
if (a.sortText > b.sortText) {
return -1;
}
}
return 0;
});
sorted.forEach((x, y) => {
x.rowElement.parentNode.insertBefore(x.rowElement, x.rowElement.parentNode.children[y]);
});
targetElem.style.cursor = null;
}
In each of my th elements, I have sort icons that I use to call this function. They have their column numbers embedded in a data tag. They look like:
<th data-field-name="lastLogin" role="columnheader" class="lastLogin">Last Login
<span class="fa fa-unsorted sort-icon" title="Sort Descending" data-col-number="6" style="font-size: 1.2em; margin-left: 15px;"></span>
</th>
The click action for the icon:
click(icon){
var parent = icon.closest('tr');
parent.querySelectorAll('.sort-icon').forEach(x => {
if (x == icon) {
return;
}
delete x.dataset.dir;
x.classList.replace('fa-sort-down', 'fa-unsorted');
x.classList.replace('fa-sort-up', 'fa-unsorted');
});
if (icon.classList.contains('fa-unsorted')) {
icon.classList.replace('fa-unsorted', 'fa-sort-up');
icon.title = icon.title.replace('Ascending', 'Descending');
icon.dataset.dir = "asc";
} else if (icon.classList.contains('fa-sort-down')) {
icon.classList.replace('fa-sort-down', 'fa-sort-up');
icon.dataset.dir = "asc";
icon.title = icon.title.replace('Ascending', 'Descending');
} else if (icon.classList.contains('fa-sort-up')) {
icon.classList.replace('fa-sort-up', 'fa-sort-down');
icon.title = icon.title.replace('Descending', 'Ascending');
icon.dataset.dir = "desc";
}
sortTable(icon.dataset.colNumber, icon.dataset.dir, icon);
}
Upvotes: 1
Reputation: 3460
I think this javascript library easy and powerful: http://tabulator.info
Tabulator allows you to create interactive tables in seconds from any HTML Table, JavaScript Array, AJAX data source or JSON formatted data.
Inside the cells you can put text, progress bar, images, other tables!
Upvotes: 0
Reputation: 7083
Apart from libraries, table sorting is quite easy to do it by yourself.
The time it takes to actually sort the rows is negligible in relation to the time the DOM needs to move items around.
The one thing that WILL give you the best performance, is to detach the rows, arrange them according to your needs and attach them again. You don't need raw JSON data, just detach the $tr's, grab the values you want to compare from td's, make an array of $tr's, sort this array according to the column you want and attach them back to your tbody.
For example, with this technique I am sorting 3000 rows of 15 columns in 1 second time, which is totally viable. With that performance, the only problem is how to fetch 3000 rows to the browser...
Upvotes: 2
Reputation: 726
I have had great success with DataTables (another jQuery plugin) with similar row numbers to what you are talking about. The speed loss you are seeing with javascript over what you have seen in java is it is actually rendering a DOM, which is a lot more work. The beauty of DataTables is you have the ability to source the data from a javascript array (essentially json) - so the sorting is done on the array (similar speed to java), and then only the part of the table the user needs to see is generated in the DOM.
See these urls for examples:
http://datatables.net/examples/data_sources/js_array.html
or
http://datatables.net/examples/data_sources/ajax.html
I suggest using the latter. If its still not fast enough using a static json array, you will want to build a serverside script to take the load off javascript - great example with serverside code here:
http://datatables.net/examples/data_sources/server_side.html
As discussed in the comments, the problem isn't the sort, but rather converting the HTML table to JS and back. This may help out by only loading rendering parts of the returned sort as the user views it; the server also provides the JS the same information as the table in JSON form. These two techniques eliminate the HTML-JS conversion and rendering problems, and thus greatly increase speed.
HTML (this is all that has to be rendered initially before the JSON comes along - add as many th tags as you have columns):
<table id="table_id">
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>etc</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
JQUERY:
$(document).ready(function() {
$('#table_id').dataTable( {
"bScrollInfinite": true,
"bScrollCollapse": true,
"sScrollY": "200px",
"bProcessing": true,
"sAjaxSource": 'array.txt'
});
});
array.txt contains:
{ "aaData": [
["This will be in column 1","This in two","this in 3"],
["another row - column 1","another two","another 3"]
]}
Upvotes: 9