14.16 Sorting Dynamic Tables
NN 6, IE 5(Win)
14.16.1 Problem
You want users to be able to view a
table sorted according to different column values.
14.16.2 Solution
Sorting a table works best when the data for the table is delivered
as JavaScript or XML data, using the kinds of table transformations
shown in Recipe
14.6 and Recipe 14.7. The table data does not need to be
any different from what was demonstrated in those recipes. The
difference is in the fixed table column headings and the functions
invoked from links surrounding the heading text.
Design your HTML structure such that clickable user interface
elements let users control the table's sorting
order. Table header text formatted as hyperlinks is most common.
Next, define JavaScript array sorting functions for each of your
sorting criteria. See the Discussion for an example. Finally, use a
script routine to generate the body of the table based on the current
sort order of the JavaScript data array (see the Discussion). Each
time the user requests a sorting of the data array, the table body is
refreshed with the data in the desired order.
14.16.3 Discussion
For an example of what a sortable table framework looks like, the
hardwired HTML portion of the table from Recipe 14.7 is shown here,
modified with th cell content fixed with clickable
links.
<table id="cupFinals">
<thead>
<tr>
<th><a href="#" title="Sort by Year"
onclick="return sortTable(this)">Year</a></th>
<th><a href="#" title="Sort by Country"
onclick="return sortTable(this)">Host Country</a></th>
<th><a href="#" title="Sort by Winning Team"
onclick="return sortTable(this)">Winner</a></th>
<th><a href="#" title="Sort by Losing Team"
onclick="return sortTable(this)">Loser</a></th>
<th>Score <a href="#" title="Sort by Winning Score"
onclick="return sortTable(this)">Win</a> - <a href="#"
title="Sort by Losing Score"
onclick="return sortTable(this)">Lose</a></th>
</tr>
</thead>
<tbody id="matchData"></tbody>
</table>
All links invoke the same sortTable(
) function, which acts as a central
switchboard to individual array sorting routines. A
switch statement branches execution based on the
text of the link's th element:
// Sorting function dispatcher (invoked by table column links)
function sortTable(link) {
switch (link.firstChild.nodeValue) {
case "Year" :
jsData.sort(sortByYear);
break;
case "Host Country" :
jsData.sort(sortByHost);
break;
case "Winner" :
jsData.sort(sortByWinner);
break;
case "Loser" :
jsData.sort(sortByLoser);
break;
case "Win" :
jsData.sort(sortByWinScore);
break;
case "Lose" :
jsData.sort(sortByLosScore);
break;
}
drawTable("matchData")
return false
}
Each of the sorting routines sorts the jsData
array based on criteria that examine a specific property of each
jsData item's object:
// Sorting functions (invoked by sortTable( ))
function sortByYear(a, b) {
return a.year - b.year;
}
function sortByHost(a, b) {
a = a.location.toLowerCase( );
b = b.location.toLowerCase( );
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
}
function sortByWinScore(a, b) {
return b.winScore - a.winScore;
}
function sortByLosScore(a, b) {
return b.losScore - a.losScore;
}
function sortByWinner(a, b) {
a = a.winner.toLowerCase( );
b = b.winner.toLowerCase( );
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
}
function sortByLoser(a, b) {
a = a.loser.toLowerCase( );
b = b.loser.toLowerCase( );
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
}
Back in the sortTable( ) function, once the
jsData table is sorted by the desired property,
the drawTable( ) function executes. This is
slightly modified over Recipe 14.7 to include a call to another
function that clears all rows from the tbody
element reserved for the dynamic cells. The modified
drawTable( ) method is as follows:
// Draw table from 'jsData' array of objects
function drawTable(tbody) {
var tr, td;
tbody = document.getElementById(tbody);
// remove existing rows, if any
clearTable(tbody);
// loop through data source
for (var i = 0; i < jsData.length; i++) {
tr = tbody.insertRow(tbody.rows.length);
td = tr.insertCell(tr.cells.length);
td.setAttribute("align", "center");
td.innerHTML = jsData[i].year;
td = tr.insertCell(tr.cells.length);
td.innerHTML = jsData[i].location;
td = tr.insertCell(tr.cells.length);
td.innerHTML = jsData[i].winner;
td = tr.insertCell(tr.cells.length);
td.innerHTML = jsData[i].loser;
td = tr.insertCell(tr.cells.length);
td.setAttribute("align", "center");
td.innerHTML = jsData[i].winScore + " - " + jsData[i].losScore;
}
}
The clearTable( ) function is a simple loop that removes
any rows in the table body section:
// Remove existing table rows
function clearTable(tbody) {
while (tbody.rows.length > 0) {
tbody.deleteRow(0);
}
}
Most of the sorting comparison functions in this recipe inspect
properties of objects that occupy each array entry. Because each
jsData array entry is an object (see the object
definition in Recipe 14.7), the comparison functions repeatedly
compare specific properties of the object, such as names of teams and
score numbers. To assure accurate string comparisons regardless of
case, they are converted to a uniform case (lowercase in the
example), so that the differing ASCII values of upper- and lowercase
values do not play a role in the comparisons.
14.16.4 See Also
Recipe 14.7 for embedding data as JavaScript objects and arrays
(which enhance table sorting possibilities); Recipe 3.5 for simple
array sorting; Recipe 3.10 for sorting an array of objects.
|