[jquery] jQuery table sort

I have a very simple HTML table with 4 columns:

Facility Name, Phone #, City, Specialty

I want the user to be able to sort by Facility Name and City only.

How can I code this using jQuery?

This question is related to jquery sorting html-table

The answer is


By far, the easiest one I've used is: http://datatables.net/

Amazingly simple...just make sure if you go the DOM replacement route (IE, building a table and letting DataTables reformat it) then make sure to format your table with <thead> and <tbody> or it won't work. That's about the only gotcha.

There's also support for AJAX, etc. As with all really good pieces of code, it's also VERY easy to turn it all off. You'd be suprised what you might use, though. I started with a "bare" DataTable that only sorted one field and then realized that some of the features were really relevant to what I'm doing. Clients LOVE the new features.

Bonus points to DataTables for full ThemeRoller support....

I've also had ok luck with tablesorter, but it's not nearly as easy, not quite as well documented, and has only ok features.


This is a nice way of sorting a table:

_x000D_
_x000D_
$(document).ready(function () {_x000D_
                $('th').each(function (col) {_x000D_
                    $(this).hover(_x000D_
                            function () {_x000D_
                                $(this).addClass('focus');_x000D_
                            },_x000D_
                            function () {_x000D_
                                $(this).removeClass('focus');_x000D_
                            }_x000D_
                    );_x000D_
                    $(this).click(function () {_x000D_
                        if ($(this).is('.asc')) {_x000D_
                            $(this).removeClass('asc');_x000D_
                            $(this).addClass('desc selected');_x000D_
                            sortOrder = -1;_x000D_
                        } else {_x000D_
                            $(this).addClass('asc selected');_x000D_
                            $(this).removeClass('desc');_x000D_
                            sortOrder = 1;_x000D_
                        }_x000D_
                        $(this).siblings().removeClass('asc selected');_x000D_
                        $(this).siblings().removeClass('desc selected');_x000D_
                        var arrData = $('table').find('tbody >tr:has(td)').get();_x000D_
                        arrData.sort(function (a, b) {_x000D_
                            var val1 = $(a).children('td').eq(col).text().toUpperCase();_x000D_
                            var val2 = $(b).children('td').eq(col).text().toUpperCase();_x000D_
                            if ($.isNumeric(val1) && $.isNumeric(val2))_x000D_
                                return sortOrder == 1 ? val1 - val2 : val2 - val1;_x000D_
                            else_x000D_
                                return (val1 < val2) ? -sortOrder : (val1 > val2) ? sortOrder : 0;_x000D_
                        });_x000D_
                        $.each(arrData, function (index, row) {_x000D_
                            $('tbody').append(row);_x000D_
                        });_x000D_
                    });_x000D_
                });_x000D_
            });
_x000D_
            table, th, td {_x000D_
            border: 1px solid black;_x000D_
        }_x000D_
        th {_x000D_
            cursor: pointer;_x000D_
        }
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>_x000D_
<table>_x000D_
        <tr><th>id</th><th>name</th><th>age</th></tr>_x000D_
        <tr><td>1</td><td>Julian</td><td>31</td></tr>_x000D_
        <tr><td>2</td><td>Bert</td><td>12</td></tr>_x000D_
        <tr><td>3</td><td>Xavier</td><td>25</td></tr>_x000D_
        <tr><td>4</td><td>Mindy</td><td>32</td></tr>_x000D_
        <tr><td>5</td><td>David</td><td>40</td></tr>_x000D_
    </table>
_x000D_
_x000D_
_x000D_

The fiddle can be found here:
https://jsfiddle.net/e3s84Luw/

The explanation can be found here: https://www.learningjquery.com/2017/03/how-to-sort-html-table-using-jquery-code


My answer would be "be careful". A lot of jQuery table-sorting add-ons only sort what you pass to the browser. In many cases, you have to keep in mind that tables are dynamic sets of data, and could potentially contain zillions of lines of data.

You do mention that you only have 4 columns, but much more importantly, you don't mention how many rows we're talking about here.

If you pass 5000 lines to the browser from the database, knowing that the actual database-table contains 100,000 rows, my question is: what's the point in making the table sortable? In order to do a proper sort, you'd have to send the query back to the database, and let the database (a tool actually designed to sort data) do the sorting for you.

In direct answer to your question though, the best sorting add-on I've come across is Ingrid. There are many reasons that I don't like this add-on ("unnecessary bells and whistles..." as you call it), but one of it's best features in terms of sort, is that it uses ajax, and doesn't assume that you've already passed it all the data before it does its sort.

I recognise that this answer is probably overkill (and over 2 years late) for your requirements, but I do get annoyed when developers in my field overlook this point. So I hope someone else picks up on it.

I feel better now.


I love this accepted answer, however, rarely do you get requirements to sort html and not have to add icons indicating the sorting direction. I took the accept answer's usage example and fixed that quickly by simply adding bootstrap to my project, and adding the following code:

<div></div>

inside each <th> so that you have a place to set the icon.

setIcon(this, inverse);

from the accepted answer's Usage, below the line:

th.click(function () {

and by adding the setIcon method:

function setIcon(element, inverse) {

        var iconSpan = $(element).find('div');

        if (inverse == false) {
            $(iconSpan).removeClass();
            $(iconSpan).addClass('icon-white icon-arrow-up');
        } else {
            $(iconSpan).removeClass();
            $(iconSpan).addClass('icon-white icon-arrow-down');
        }
        $(element).siblings().find('div').removeClass();
    }

Here is a demo. --You need to either run the demo in Firefox or IE, or disable Chrome's MIME-type checking for the demo to work. It depends on the sortElements Plugin, linked by the accepted answer, as an external resource. Just a heads up!


This one does not hang up the browser/s, easy configurable further:

var table = $('table');

$('th.sortable').click(function(){
    var table = $(this).parents('table').eq(0);
    var ths = table.find('tr:gt(0)').toArray().sort(compare($(this).index()));
    this.asc = !this.asc;
    if (!this.asc)
       ths = ths.reverse();
    for (var i = 0; i < ths.length; i++)
       table.append(ths[i]);
});

function compare(idx) {
    return function(a, b) {
       var A = tableCell(a, idx), B = tableCell(b, idx)
       return $.isNumeric(A) && $.isNumeric(B) ? 
          A - B : A.toString().localeCompare(B)
    }
}

function tableCell(tr, index){ 
    return $(tr).children('td').eq(index).text() 
}

I came across this, and thought I'd throw in my 2 cents. Click on the column headers to sort ascending, and again to sort descending.

  • Works in Chrome, Firefox, Opera AND IE(8)
  • Only uses JQuery
  • Does alpha and numeric sorting - ascending and descending

_x000D_
_x000D_
$('th').click(function(){_x000D_
    var table = $(this).parents('table').eq(0)_x000D_
    var rows = table.find('tr:gt(0)').toArray().sort(comparer($(this).index()))_x000D_
    this.asc = !this.asc_x000D_
    if (!this.asc){rows = rows.reverse()}_x000D_
    for (var i = 0; i < rows.length; i++){table.append(rows[i])}_x000D_
})_x000D_
function comparer(index) {_x000D_
    return function(a, b) {_x000D_
        var valA = getCellValue(a, index), valB = getCellValue(b, index)_x000D_
        return $.isNumeric(valA) && $.isNumeric(valB) ? valA - valB : valA.toString().localeCompare(valB)_x000D_
    }_x000D_
}_x000D_
function getCellValue(row, index){ return $(row).children('td').eq(index).text() }
_x000D_
table, th, td {_x000D_
    border: 1px solid black;_x000D_
}_x000D_
th {_x000D_
    cursor: pointer;_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
<table>_x000D_
    <tr><th>Country</th><th>Date</th><th>Size</th></tr>_x000D_
    <tr><td>France</td><td>2001-01-01</td><td>25</td></tr>_x000D_
    <tr><td><a href=#>spain</a></td><td>2005-05-05</td><td></td></tr>_x000D_
    <tr><td>Lebanon</td><td>2002-02-02</td><td>-17</td></tr>_x000D_
    <tr><td>Argentina</td><td>2005-04-04</td><td>100</td></tr>_x000D_
    <tr><td>USA</td><td></td><td>-6</td></tr>_x000D_
</table>
_x000D_
_x000D_
_x000D_

** Update: 2018


Here's a chart that may be helpful deciding which to use: http://blog.sematext.com/2011/09/19/top-javascript-dynamic-table-libraries/


To the response of James I will only change the sorting function to make it more universal. This way it will sort text alphabetical and numbers like numbers.

if( $.text([a]) == $.text([b]) )
    return 0;
if(isNaN($.text([a])) && isNaN($.text([b]))){
    return $.text([a]) > $.text([b]) ? 
       inverse ? -1 : 1
       : inverse ? 1 : -1;
}
else{
    return parseInt($.text([a])) > parseInt($.text([b])) ? 
      inverse ? -1 : 1
      : inverse ? 1 : -1;
}

You can use a jQuery plugin (breedjs) that provides sort, filter and pagination:

HTML:

<table>
  <thead>
    <tr>
      <th sort='name'>Name</th>
      <th>Phone</th>
      <th sort='city'>City</th>
      <th>Speciality</th>
    </tr>
  </thead>
  <tbody>
    <tr b-scope="people" b-loop="person in people">
      <td b-sort="name">{{person.name}}</td>
      <td>{{person.phone}}</td>
      <td b-sort="city">{{person.city}}</td>
      <td>{{person.speciality}}</td>
    </tr>
  </tbody>
</table>

JS:

$(function(){
  var data = {
    people: [
      {name: 'c', phone: 123, city: 'b', speciality: 'a'},
      {name: 'b', phone: 345, city: 'a', speciality: 'c'},
      {name: 'a', phone: 234, city: 'c', speciality: 'b'},
    ]
  };
  breed.run({
    scope: 'people',
    input: data
  });
  $("th[sort]").click(function(){
    breed.sort({
      scope: 'people',
      selector: $(this).attr('sort')
    });
  });
});

Working example on fiddle


Another approach to sort HTML table. (based on W3.JS HTML Sort)

_x000D_
_x000D_
/* Facility Name */_x000D_
$('#bioTable th:eq(0)').addClass("control-label pointer");_x000D_
/* Phone # */_x000D_
$('#bioTable th:eq(1)').addClass("not-allowed");_x000D_
/* City */_x000D_
$('#bioTable th:eq(2)').addClass("control-label pointer");_x000D_
/* Specialty */_x000D_
$('#bioTable th:eq(3)').addClass("not-allowed");_x000D_
_x000D_
_x000D_
var collection = [{_x000D_
  "FacilityName": "MinION",_x000D_
  "Phone": "999-8888",_x000D_
  "City": "France",_x000D_
  "Specialty": "Genetic Prediction"_x000D_
}, {_x000D_
  "FacilityName": "GridION X5",_x000D_
  "Phone": "999-8812",_x000D_
  "City": "Singapore",_x000D_
  "Specialty": "DNA Assembly"_x000D_
}, {_x000D_
  "FacilityName": "PromethION",_x000D_
  "Phone": "929-8888",_x000D_
  "City": "San Francisco",_x000D_
  "Specialty": "DNA Testing"_x000D_
}, {_x000D_
  "FacilityName": "iSeq 100 System",_x000D_
  "Phone": "999-8008",_x000D_
  "City": "Christchurch",_x000D_
  "Specialty": "gDNA-mRNA sequencing"_x000D_
}]_x000D_
_x000D_
$tbody = $("#bioTable").append('<tbody></tbody>');_x000D_
_x000D_
for (var i = 0; i < collection.length; i++) {_x000D_
  $tbody = $tbody.append('<tr class="item"><td>' + collection[i]["FacilityName"] + '</td><td>' + collection[i]["Phone"] + '</td><td>' + collection[i]["City"] + '</td><td>' + collection[i]["Specialty"] + '</td></tr>');_x000D_
}
_x000D_
.control-label:after {_x000D_
  content: "*";_x000D_
  color: red;_x000D_
}_x000D_
_x000D_
.pointer {_x000D_
  cursor: pointer;_x000D_
}_x000D_
_x000D_
.not-allowed {_x000D_
  cursor: not-allowed;_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
<script src="https://www.w3schools.com/lib/w3.js"></script>_x000D_
<link href="https://www.w3schools.com/w3css/4/w3.css" rel="stylesheet" />_x000D_
<p>Click the <strong>table headers</strong> to sort the table accordingly:</p>_x000D_
_x000D_
<table id="bioTable" class="w3-table-all">_x000D_
  <thead>_x000D_
    <tr>_x000D_
      <th onclick="w3.sortHTML('#bioTable', '.item', 'td:nth-child(1)')">Facility Name</th>_x000D_
      <th>Phone #</th>_x000D_
      <th onclick="w3.sortHTML('#bioTable', '.item', 'td:nth-child(3)')">City</th>_x000D_
      <th>Specialty</th>_x000D_
    </tr>_x000D_
  </thead>_x000D_
</table>
_x000D_
_x000D_
_x000D_


We just started using this slick tool: https://plugins.jquery.com/tablesorter/

There is a video on its use at: http://www.highoncoding.com/Articles/695_Sorting_GridView_Using_JQuery_TableSorter_Plug_in.aspx

    $('#tableRoster').tablesorter({
        headers: {
            0: { sorter: false },
            4: { sorter: false }
        }
    });

With a simple table

<table id="tableRoster">
        <thead> 
                  <tr>
                    <th><input type="checkbox" class="rCheckBox" value="all" id="rAll" ></th>
                    <th>User</th>
                    <th>Verified</th>
                    <th>Recently Accessed</th>
                    <th>&nbsp;</th>
                  </tr>
        </thead>

I ended up using Nick's answer (the most popular but not accepted) https://stackoverflow.com/a/19947532/5271220

and combined it with the https://stackoverflow.com/a/16819442/5271220 but didn't want to add icons or fontawesome to the project. The CSS styles for sort-column-asc/desc I did color, padding, rounded border.

I also modified it to go by class rather than by any so we could control which ones are sortable. This could also come in handy later if there are two tables although more modifications would need to be done for that.

body:

 html += "<thead>\n";
    html += "<th></th>\n";
    html += "<th class=\"sort-header\">Name <span></span></i></th>\n";
    html += "<th class=\"sort-header\">Status <span></span></th>\n";
    html += "<th class=\"sort-header\">Comments <span></span></th>\n";
    html += "<th class=\"sort-header\">Location <span></span></th>\n";
    html += "<th nowrap class=\"sort-header\">Est. return <span></span></th>\n";
    html += "</thead>\n";
    html += "<tbody>\n"; ...

... further down the body

$("body").on("click", ".sort-header", function (e) {
    var table = $(this).parents('table').eq(0)
    var rows = table.find('tr:gt(0)').toArray().sort(comparer($(this).index()))
    this.asc = !this.asc
    if (!this.asc) { rows = rows.reverse() }
    for (var i = 0; i < rows.length; i++) { table.append(rows[i]) }

    setIcon(e.target, this.asc);
});

functions:

function comparer(index) {
        return function (a, b) {
            var valA = getCellValue(a, index), valB = getCellValue(b, index)
            return $.isNumeric(valA) && $.isNumeric(valB) ? valA - valB : valA.toString().localeCompare(valB)
        }
    }

    function getCellValue(row, index) {
        return $(row).children('td').eq(index).text()
    }

    function setIcon(element, inverse) {

        var iconSpan = $(element).find('span');

        if (inverse == true) {
            $(iconSpan).removeClass();
            $(iconSpan).addClass('sort-column-asc');
            $(iconSpan)[0].innerHTML = " &#8593 " // arrow up
        } else {
            $(iconSpan).removeClass();
            $(iconSpan).addClass('sort-column-desc');
            $(iconSpan)[0].innerHTML = " &#8595 " // arrow down 
        }

        $(element).siblings().find('span').each(function (i, obj) {
            $(obj).removeClass();
            obj.innerHTML = "";
        });
    }

@Nick Grealy's answer is great, but it does not take into account possible rowspan attributes of the table header cells (and probably the other answers don't do it either). Here is an improvement of the @Nick Grealy's answer which fixes that. Based on this answer too (thanks @Andrew Orlov).

I've also replaced the $.isNumeric function with a custom one (thanks @zad) to make it work with older jQuery versions.

To activate it, add class="sortable" to the <table> tag.

$(document).ready(function() {

    $('table.sortable th').click(function(){
        var table = $(this).parents('table').eq(0);
        var column_index = get_column_index(this);
        var rows = table.find('tbody tr').toArray().sort(comparer(column_index));
        this.asc = !this.asc;
        if (!this.asc){rows = rows.reverse()};
        for (var i = 0; i < rows.length; i++){table.append(rows[i])};
    })

});

function comparer(index) {
    return function(a, b) {
        var valA = getCellValue(a, index), valB = getCellValue(b, index);
        return isNumber(valA) && isNumber(valB) ? valA - valB : valA.localeCompare(valB);
    }
}
function getCellValue(row, index){ return $(row).children('td').eq(index).html() };

function isNumber(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

function get_column_index(element) {
    var clickedEl = $(element);
    var myCol = clickedEl.closest("th").index();
    var myRow = clickedEl.closest("tr").index();
    var rowspans = $("th[rowspan]");
    rowspans.each(function () {
        var rs = $(this);
        var rsIndex = rs.closest("tr").index();
        var rsQuantity = parseInt(rs.attr("rowspan"));
        if (myRow > rsIndex && myRow <= rsIndex + rsQuantity - 1) {
            myCol++;
        }
    });
    // alert('Row: ' + myRow + ', Column: ' + myCol);
    return myCol;
};

My vote! jquery.sortElements.js and simple jquery
Very simple, very easy, thanks nandhp...

            $('th').live('click', function(){

            var th = $(this), thIndex = th.index(), var table = $(this).parent().parent();

                switch($(this).attr('inverse')){
                case 'false': inverse = true; break;
                case 'true:': inverse = false; break;
                default: inverse = false; break;
                }
            th.attr('inverse',inverse)

            table.find('td').filter(function(){
                return $(this).index() === thIndex;
            }).sortElements(function(a, b){
                return $.text([a]) > $.text([b]) ?
                    inverse ? -1 : 1
                    : inverse ? 1 : -1;
            }, function(){
                // parentNode is the element we want to move
                return this.parentNode; 
            });
            inverse = !inverse;     
            });

Dei uma melhorada do código
One cod better! Function for All tables in all Th in all time... Look it!
DEMO


Examples related to jquery

How to make a variable accessible outside a function? Jquery assiging class to th in a table Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Getting all files in directory with ajax Bootstrap 4 multiselect dropdown Cross-Origin Read Blocking (CORB) bootstrap 4 file input doesn't show the file name Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource how to remove json object key and value.?

Examples related to sorting

Sort Array of object by object field in Angular 6 Sorting a list with stream.sorted() in Java How to sort dates from Oldest to Newest in Excel? how to sort pandas dataframe from one column Reverse a comparator in Java 8 Find the unique values in a column and then sort them pandas groupby sort within groups pandas groupby sort descending order Efficiently sorting a numpy array in descending order? Swift: Sort array of objects alphabetically

Examples related to html-table

Table column sizing DataTables: Cannot read property 'length' of undefined TypeError: a bytes-like object is required, not 'str' in python and CSV How to get the <td> in HTML tables to fit content, and let a specific <td> fill in the rest How to stick table header(thead) on top while scrolling down the table rows with fixed header(navbar) in bootstrap 3? Sorting table rows according to table header column using javascript or jquery How to make background of table cell transparent How to auto adjust table td width from the content bootstrap responsive table content wrapping How to print table using Javascript?