7
votes

Suppose I have a table with fields

Rank, Id and Name

On clicking the Rank , the table gets sorted by rank in ascending order using this code

$(function() {
    $("#rank").click(function() {
        var rows = $("#rank_table tbody tr").get();
        rows.sort(sortTable);
        $.each(rows, function(index, row) {
            $("#rank_table").children("tbody").append(row);
        });
    });
});

function sortTable(a, b) {
    var A = parseInt($(a).children('td').eq(0).text());
    var B = parseInt($(b).children('td').eq(0).text());
    if (A < B) return -1;
    if (A > B) return 1;
    return 0;
}

Rank and Id are integers with id rank and st_id respectively. So, What I want to achieve is that when I click on Rank field once, table gets sorted in ascending order and again clicking it sorts the table in descending order.

I want to do this for both the fields- rank and Id. For descending, do I need to use a different function other than ascending this ascending function.

How can I achieve this using jQuery and this sort() function(not plugins)?

Here is the html

<!Doctype html>
<html>
<head>
    <style>
        #thead {
            cursor: pointer;
            text-decoration: underline;
            text-align: center;
        }

        #tbody {
            text-align: center;
        }
    </style>
    <script src="libs/jquery-1.5.1.js" type="text/javascript"></script>
    <script src="table_sort.js" type="text/javascript"></script>
</head>

<body>
    <table id="rank_table">
        <thead id="thead">
            <tr>
                <th id="rank">Rank</th>
                <th id="st_id">Student_id</th>
                <th id="st_name">Name</th>
            </tr>
        </thead>
        <tbody id="tbody">
            <tr>
                <td>3</td>
                <td>2</td>
                <td>Ted</td>
            </tr>
            <tr>
                <td>2</td>
                <td>1</td>
                <td>John</td>
            </tr>
            <tr>
                <td>5</td>
                <td>4</td>
                <td>Neil</td>
            </tr>
            <tr>
                <td>1</td>
                <td>5</td>
                <td>Alex</td>
            </tr>
            <tr>
                <td>4</td>
                <td>3</td>
                <td>Nave</td>
            </tr>
        </tbody>
    </table>

</body>

</html>
2
The easiest way to do this would be to set a data attribute or class name on your sortable column indicating how it is currently being sorted. Then, in your click handler, check what the current sort is and pick which sort function to use at that time (and update the attribute/class). - Shmiddty
Something like this @Shmiddty code if($("#rank")).hasClass('desc')){ return (A == B ? 0 : (A > B ? 1 : -1)); $("#rank").removeClass('desc'); $("#rank").addClass('asc'); } else { return (A == B ? 0 : (A > B ? 1 : -1)); $("#rank").removeClass('asc'); $("#rank").addClass('desc'); }code - Alonso
It could be as simple as calling rows.reverse() when it should be sorted in descending order. - Shmiddty
yeah, this is a good option to use. - Alonso

2 Answers

9
votes

I would probably re-write it to something like this: http://jsfiddle.net/gQNPt/1/

$(".sortable").click(function(){
    var o = $(this).hasClass('asc') ? 'desc' : 'asc';
    $('.sortable').removeClass('asc').removeClass('desc');
    $(this).addClass(o);

    var colIndex = $(this).prevAll().length;
    var tbod = $(this).closest("table").find("tbody");
    var rows = tbod.find("tr");

    rows.sort(function(a,b){
        var A = $(a).find("td").eq(colIndex).text();
        var B = $(b).find("td").eq(colIndex).text();

        if (!isNaN(A)) A = Number(A);
        if (!isNaN(B)) B = Number(B);

        return o == 'asc' ? A > B : B > A;
    });

    $.each(rows, function(index, ele){
        tbod.append(ele);
    });
});

HTML

<table id="fruits">
    <thead>
        <tr>
            <th class="sortable asc">ID</th>
            <th class="sortable">Name</th>
            <th class="sortable">Rank</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>0</td>
            <td>Banana</td>
            <td>15</td>
        </tr>
        <tr>
            <td>1</td>
            <td>Pear</td>
            <td>3</td>
        </tr>
        <tr>
            <td>2</td>
            <td>Orange</td>
            <td>6</td>
        </tr>
        <tr>
            <td>3</td>
            <td>Apple</td>
            <td>14</td>
        </tr>
        <tr>
            <td>4</td>
            <td>Mango</td>
            <td>99</td>
        </tr>
    </tbody>
</table>​

You can then control which columns are sortable by adding the class "sortable" to the column header.

3
votes

If your current function sorts it ascending, you should only have to change your if statements to get it descending?

if (A > B) return -1;
if (A < B) return 1;

This works the way you want:

$(function() {
    $("#rank").on('click', function() {
        var rows = $("#rank_table tbody tr").get();
        rows.sort(sortTable);
        $.each(rows, function(index, row) {
            $("#rank_table").children("tbody").append(row);
        });
        if (ascending) {
            ascending = false;
        } else {
            ascending = true;
        }
    });
});

var ascending = false;

function sortTable(a, b) {
    var A = parseInt($(a).children('td').eq(0).text(), 10);
    var B = parseInt($(b).children('td').eq(0).text(), 10);


    if (ascending) {
        if (A > B) return 1;
        if (A < B) return -1;
    } else {
        if (A > B) return -1;
        if (A < B) return 1;
    }
    return 0;

}