Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting tbody elements by column value with jQuery

I am trying to sort a table - so when a user clicks on the table heading, it will sort in ascending/descending order. I've got it to the point where I can sort the table based on the column value. However, I have groupings of table rows (two rows per table body), and I want to sort the columns based on the values in the columns of the first row of each table body, but when it reorders the table, it want it to reorder the table bodies, not the table rows.

<table width="100%" id="my-tasks" class="gen-table">
<thead>
    <tr>
        <th class="sortable"><p>Name</p></th>
        <th class="sortable"><p>Project</p></th>
        <th class="sortable"><p>Priority</p></th>
        <th class="sortable"><p>%</p></th>
    </tr>
</thead>

<tbody>
<tr class="sortable-row" id="44">
    <td><p>dfgdf</p></td><td><p>Test</p></td>
    <td><p>1</p></td><td><p>0</p></td>
</tr>
<tr>
    <td></td>
    <td colspan="3"><p>asdfds</p></td>
</tr>
</tbody>

<tbody>
<tr class="sortable-row" id="43">
    <td><p>a</p></td>
    <td><p>Test</p></td>
    <td><p>1</p></td>
    <td><p>11</p></td>
</tr>
<tr>
    <td></td>
    <td colspan="3"><p>asdf</p></td>
</tr>
</tbody>

<tbody>
<tr class="sortable-row" id="40">
    <td><p>Filter Tasks</p></td>
    <td><p>Propel</p></td>
    <td><p>10</p></td>
    <td><p>10</p></td>
</tr>
<tr>
    <td></td>
    <td colspan="3"><p>Add a button to filter tasks.</p></td>
</tr>
</tbody>
</table>

With the following javascript:

jQuery(document).ready(function () {
    jQuery('thead th').each(function(column) {
        jQuery(this).addClass('sortable').click(function() {

            var findSortKey = function($cell) {
                return $cell.find('.sort-key').text().toUpperCase() + ' ' + $cell.text().toUpperCase();
            };
            var sortDirection = jQuery(this).is('.sorted-asc') ? -1 : 1;

            var $rows = jQuery(this).parent().parent().parent().find('.sortable-row').get();
            jQuery.each($rows, function(index, row) {
                row.sortKey = findSortKey(jQuery(row).children('td').eq(column));
            });

            $rows.sort(function(a, b) {
                if (a.sortKey < b.sortKey) return -sortDirection;
                if (a.sortKey > b.sortKey) return sortDirection;
                return 0;
            });

            jQuery.each($rows, function(index, row) {
                jQuery('#propel-my-tasks').append(row);
                row.sortKey = null;
            });

            jQuery('th').removeClass('sorted-asc sorted-desc');
            var $sortHead = jQuery('th').filter(':nth-child(' + (column + 1) + ')');
            sortDirection == 1 ? $sortHead.addClass('sorted-asc') : $sortHead.addClass('sorted-desc');

            jQuery('td').removeClass('sorted').filter(':nth-child(' + (column + 1) + ')').addClass('sorted');

        });
    });
});
like image 859
v0idless Avatar asked Oct 10 '22 23:10

v0idless


1 Answers

You need to sort the tbody elements, not the row elements. You said that yourself in your description of the problem, but your code actually sorts rows, not tbodies.

A secondary problem is that your sort treats everything as a string, which breaks when sorting 1-digit numeric strings ("2") against two-digit strings ("10").

To fix, replace this:

        var $rows = jQuery(this).parent().parent().parent()
            .find('.sortable-row').get();
        jQuery.each($rows, function(index, row) {
            row.sortKey = findSortKey(jQuery(row).children('td').eq(column));
        });

with this:

        var $tbodies = jQuery(this).parent().parent().parent()
            .find('.sortable-row').parent().get();
        jQuery.each($tbodies, function(index, tbody) {
            var x = findSortKey(jQuery(tbody).find('tr > td').eq(column));
            var z = ~~(x); // if integer, z == x
            tbody.sortKey = (z == x) ? z : x;
        });

And then replace $rows with $tbodies throughout your script, and row with tbody.

Example:
http://jsbin.com/oxuva5

like image 72
Cheeso Avatar answered Oct 16 '22 15:10

Cheeso