Programming4us
         
 
 
Programming

jQuery 1.3 : Sorting and paging (part 3) - Using a comparator to sort table rows

12/28/2010 3:00:28 PM
Basic alphabetical sorting

Now let's perform a sort on the Title column of the table. We'll need a class on the table header cell so that we can select it properly:

<thead>
<tr>
<th></th>
<th class="sort-alpha">Title</th>
<th>Author(s)</th>
<th>Publish&nbsp;Date</th>
<th>Price</th>
</tr>
</thead>

Using JavaScript to sort arrays

To perform the actual sort, we can use JavaScript's built in .sort() method. It does an in-place sort on an array, and can take a comparator function as an argument. This function compares two items in the array and should return a positive or negative number depending on which item should come first in the sorted array.

For example, take a simple array of numbers:

var arr = [52, 97, 3, 62, 10, 63, 64, 1, 9, 3, 4];

We can sort this array by calling arr.sort(). After this, the items are in the order:

[1, 10, 3, 3, 4, 52, 62, 63, 64, 9, 97]

By default, as we see here, the items are sorted lexicographically (in alphabetical order). In this case it might make more sense to sort the items numerically. To do this, we can supply a comparator function to the .sort() method:

arr.sort(function(a,b) {
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
});

This function returns a negative number if a should come first in the sorted array, a positive number if b should come first, and zero if the order of the items does not matter. With this information in hand, the .sort() method can sequence the items appropriately:

[1, 3, 3, 4, 9, 10, 52, 62, 63, 64, 97]

Using a comparator to sort table rows

Our initial sort routine looks like this:

$(document).ready(function() {
$('table.sortable').each(function() {
var $table = $(this);
$('th', $table).each(function(column) {
var $header = $(this);
if ($header.is('.sort-alpha')) {
$header.addClass('clickable').hover(function() {
$header.addClass('hover');
}, function() {
$header.removeClass('hover');
}).click(function() {
var rows = $table.find('tbody > tr').get();
rows.sort(function(a, b) {
var keyA = $(a).children('td').eq(column).text()
.toUpperCase();
var keyB = $(b).children('td').eq(column).text()
.toUpperCase();
if (keyA < keyB) return -1;
if (keyA > keyB) return 1;
return 0;
});
$.each(rows, function(index, row) {
$table.children('tbody').append(row);
});
});
}
});
});
});


The first thing to note is our use of the .each() method to make the iteration explicit. Even though we could bind a click handler to all headers that have the sort-alpha $('table.sortable th.sort-alpha').click(), this wouldn't allow us to easily capture a crucial bit of information: the column index of the clicked header. Because .each() passes the iteration index into its callback function, we can use it to find the relevant cell in each row of the data later. class just by calling

Once we have found the header cell, we retrieve an array of all of the data rows. This is a great example of how .get() is useful in transforming a jQuery object into an array of DOM nodes; even though jQuery objects act like arrays in many respects, they don't have any of the native array methods available, such as .sort().

Now that we have an array of DOM nodes, we can sort them, but to do this we need to write an appropriate comparator function. We want to sort the rows according to the textual contents of the relevant table cells, so this will be the information the comparator function will examine. We know which cell to look at because we captured the column index in the enclosing .each() call. We convert the text to uppercase because string comparisons in JavaScript are case-sensitive and we wish our sort to be case-insensitive. We store the key values in variables to avoid redundant calculations, compare them, and return a positive or negative number as discussed above.

Finally, with the array sorted, we loop through the rows and reinsert them into the table. Since .append() does not clone nodes, this moves them rather than copying them. Our table is now sorted.

This is an example of progressive enhancement's counterpart, graceful degradation. Unlike the AJAX solution discussed earlier, this technique cannot function without JavaScript; we are assuming the server has no scripting language available to it for this example. Since JavaScript is required for the sort to work, we are adding the class through code only, thereby making sure that the interface indicates that sorting is possible (with a background image) only if the script can run. The page degrades into one that is still functional, albeit without sorting available. clickable

We have moved the actual rows around, hence our alternating row colors are now out of whack:

We need to reapply the row colors after the sort is performed. We can do this by pulling the coloring code out into a function that we call when needed:

$(document).ready(function() {
var alternateRowColors = function($table) {
$('tbody tr:odd', $table)
.removeClass('even').addClass('odd');
$('tbody tr:even', $table)
.removeClass('odd').addClass('even');
};

$('table.sortable').each(function() {
var $table = $(this);
alternateRowColors($table);

$('th', $table).each(function(column) {
var $header = $(this);
if ($header.is('.sort-alpha')) {
$header.addClass('clickable').hover(function() {
$header.addClass('hover');
}, function() {
$header.removeClass('hover');
}).click(function() {
var rows = $table.find('tbody > tr').get();
rows.sort(function(a, b) {
var keyA = $(a).children('td').eq(column).text()
.toUpperCase();
var keyB = $(b).children('td').eq(column).text()
.toUpperCase();
if (keyA < keyB) return -1;
basic alphabetical sorting, JavaScript sortingcomparator, usingif (keyA > keyB) return 1;
return 0;
});
$.each(rows, function(index, row) {
$table.children('tbody').append(row);
});
alternateRowColors($table);

});
}
});
});
});


This corrects the row coloring after the fact, fixing our issue:

Other -----------------
- Coding JavaScript for Mobile Browsers (part 5)
- Coding JavaScript for Mobile Browsers (part 4)
- Coding JavaScript for Mobile Browsers (part 3) - Writing to the document
- Coding JavaScript for Mobile Browsers (part 1) - Standard dialogs
- Coding JavaScript for Mobile Browsers (part 1) - Code Execution
- Programming the Mobile Web : JavaScript Mobile - Supported Technologies
- Security in Cloud Computing (part 4) - Audit and Compliance
- Security in Cloud Computing (part 3)
- Security in Cloud Computing (part 2) - Identity and Access Management
- Security in Cloud Computing (part 1) - Data Security and Storage
- Cloud Security and Privacy : Analyst Predictions
- CSS for Mobile Browsers : WebKit Extensions (part 2) - Border Image
- CSS for Mobile Browsers : WebKit Extensions (part 1) - Text Stroke and Fill
- jQuery 1.3 : Working with numeric form data (part 9) - The finished code
- jQuery 1.3 : Working with numeric form data (part 8) - Editing shipping information
- jQuery 1.3 : Working with numeric form data (part 7) - Deleting items
- jQuery 1.3 : Working with numeric form data (part 6) - Finishing touches
- jQuery 1.3 : Working with numeric form data (part 5)
- jQuery 1.3 : Working with numeric form data (part 4) - Dealing with decimal places
- jQuery 1.3 : Working with numeric form data (part 3) - Parsing and formatting currency
 
 
Most View
- Windows 8 : Applications - Installing or Removing a Program
- Managing Windows Server 2012 Storage and File Systems : Storage Management (part 13) - Managing volumes on dynamic disks - Configuring RAID 1, Mirroring boot and system volumes
- Windows Phone 7 : Changing Caller ID Settings
- SharePoint 2010 : Word Automation Services - Demonstration Scenario (part 3) - Combine Documents Using OpenXML, Converting an OpenXML Document to an Alternative Format
- Windows 7 : Understanding User Account Control (part 1) - Elevating Privileges
- Programming with SQL Azure : Connecting to SQL Azure (part 1) - ADO.NET
- Windows Phone 7 : Using Word Mobile
- Windows Server 2008 R2 : Installing Windows SharePoint Services (part 1)
- jQuery 1.3 : Working with numeric form data (part 5)
- Windows Server 2008 R2 and Windows 7 : Deploying Branchcache (part 1)
Top 10
- Implementing Edge Services for an Exchange Server 2007 Environment : Utilizing the Basic Sender and Recipient Connection Filters (part 3) - Configuring Recipient Filtering
- Implementing Edge Services for an Exchange Server 2007 Environment : Utilizing the Basic Sender and Recipient Connection Filters (part 2)
- Implementing Edge Services for an Exchange Server 2007 Environment : Utilizing the Basic Sender and Recipient Connection Filters (part 1)
- Implementing Edge Services for an Exchange Server 2007 Environment : Installing and Configuring the Edge Transport Server Components
- What's New in SharePoint 2013 (part 7) - BCS
- What's New in SharePoint 2013 (part 6) - SEARCH
- What's New in SharePoint 2013 (part 6) - WEB CONTENT MANAGEMENT
- What's New in SharePoint 2013 (part 5) - ENTERPRISE CONTENT MANAGEMENT
- What's New in SharePoint 2013 (part 4) - WORKFLOWS
- What's New in SharePoint 2013 (part 3) - REMOTE EVENTS