HTML tables can be sorted using JavaScript, giving a much more responsive interface than when using server-side code. However, naïve implementations often behave in a counterintuitive way, sorting numbers alphabetically and sorting table footers along with table data. Furthermore, few implementations allow content authors to take full advantage of HTML within sortable tables, by being incapable of sorting cells that contain formatting or span multiple columns. SortableTable can be added rapidly to simple tables, while facilitating the implementation of advanced sortable tables using complex sorting orders. An example is shown below, combining table headers, table footers, cells spanning multiple columns, text with formatting, Unicode text, and cells containing numbers with various units.
| Name | Local Name | Life Expectancy | Pop. Density | GDP Per Capita |
|---|---|---|---|---|
| Name | Local Name | Life Expectancy | Pop. Density | GDP Per Capita |
| Japan | 日本 | 82.6 years | 337/km² | $38341 |
| Hong Kong | 香港 | 82.2 years | 6352/km² | $27466 |
| Iceland | Ísland | 81.8 years | 3.1/km² | $54858 |
| Switzerland | die Schweiz | 81.7 years | 188/km² | $50532 |
| Australia | 81.2 years | 2.6/km² | $39320 | |
Using SortableTable
| File | Size | Description |
|---|---|---|
| SortableTable.js | 15840 bytes | Full version with comments |
| SortableTable.compressed.js | 3863 bytes | Compressed version |
Download one of the files listed above and upload it to your website. Link to it from your page with code such as:
<script type="text/javascript" src="SortableTable.js"></script>
SortableTable makes use of the full HTML table syntax. Parts of the table that are sortable should be placed in tbody elements — multiple tbody elements may be used to create independently sortable sections of the table — while non-sortable headings should be placed in thead and tfoot elements. For example:
<table id="countryData">
<thead>
<tr>
<th>Country</th>
<th>Capital</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Country</th>
<th>Capital</th>
</tr>
</tfoot>
<tbody>
<tr>
<th>India</th>
<th>New Delhi</th>
</tr>
<tr>
<th>Pakistan</th>
<th>Islamabad</th>
</tr>
</tbody>
</table>
The table can be made sortable by creating a new instance of SortableTable, passing it a reference to the table node. For example:
var countryData = new SortableTable(document.getElementById('countryData'));
Note that the table’s document tree node must already exist when the constructor is called. This can be done either by including the JavaScript code below the table in the document source, or by calling the constructor when the document has loaded — one way to do this is by using the OnloadScheduler.
The simplest way to add sorting options to the table is to use the convenience function addSortImages, which adds images that the visitor can click to sort the table. This function requires the seven parameters:
- includeFooter
- This should be set to true if the sorting images should also be added to headers in the tfoot element — otherwise only headers in the thead element have images added.
- ascendingImageFirst
- This should be set to true if the ascending image should be placed first in the document tree, and false otherwise.
- comparisonFunctions
- An array of comparison functions to use when sorting columns. The array should have at least as many elements as there are columns - extra elements are ignored. The standard comparison functions can be accessed as SortableTable.SORT.ALPHABETICAL, SortableTable.SORT.NUMERICAL, and SortableTable.SORT.ALPHANUMERICAL. Comparison functions are discussed in more detail below.
- ascendingImageURL
- The URL of the ascending image.
- descendingImageURL
- The URL of the descending image.
- imageWidth
- The width of each image, in pixels.
- imageHeight
- The height of each image, in pixels.
For example:
countryData.addSortImages(
true,
true,
[
SortableTable.SORT.ALPHABETICAL,
SortableTable.SORT.ALPHABETICAL,
],
'ascending.png',
'descending.png',
17,
11);
The images are added to the document tree as two img elements with the classes sortableTableAscendingImage and sortableTableDescendingImage, inside a span element with class sortableTableSortImages, giving a range of formatting options. For example, the following CSS displays the the two images under the header text with some space between them, and changes the cursor to ‘pointer’ (which is usually rendered as a hand):
.sortableTableSortImages{
display:block;
line-height:0;
}
.sortableTableSortImages img{
margin:2px 8px;
cursor:pointer;
}
Comparison functions
While the addSortImages function provides a convenient way to add sorting options to a table, the sort function does the real work. The sort functions takes three parameters:
- column
- This is the index of the column by which to sort. Indices are 0-based (that is, the first column is column 0).
- comparisonFunction
- The function to use in comparisons. Comparison functions are discussed in more detail below.
- ascending
- This should be set to true to sort the column in ascending order, or false to sort the column in descending order.
For example:
countryData.sort(0, SortableTable.SORT.ALPHABETICAL, true);
Comparison functions are a powerful feature of SortableTable, allowing sorting by arbitrary criteria. Three standard comparison functions are provided:
- SortableTable.SORT.ALPHABETICAL
- A simple alphabetical comparison. This comparison applies the less than operator to the two strings.
- SortableTable.SORT.NUMERICAL
- A simple numerical comparison. This comparison applies the subtraction operator to the two strings to convert them into numbers and determine which is larger.
- SortableTable.SORT.ALPHANUMERICAL
- An alphanumerical sort. Conceptually, this treats consecutive digits inside a string as a single character, sorted before all normal characters but compared numberically with other such strings of digits. For example, the following strings are in order based on this comparison: 2, 11, a, a2, a11, a11b, a11b2, and a11b11
Custom comparison functions
Developers may wish to use their own functions. A comparison function should take up to four parameters:
- cellText1 — the text content of the first cell
- cellText2 — the text content of the second cell
- cellNode1 — the DOM node of the first cell
- cellNode2 — the DOM node of the second cell
If the comparison does not need to take into account DOM nodes, these parameters can be omitted — the standard functions do this. Note that the text is normalised — leading and trailing whitespace is removed and consecutive whitespace characters are replaced with a single space.
The function should return an integer. A value of 0 means that the two cells should be considered equal. A value less than 0 means that the first cell should be sorted before the second cell (when in ascending order). A value greater than 0 means that the first cell should be sorted after the second cell (when in ascending order).
For example, the standard numerical sort uses the following code:
function(cellText1, cellText2){
return cellText1 - cellText2;
}
Dynamic tables
Dynamic tables (those whose content changes after the page has loaded) make sorting more complicated. An internal model of the table is used to make sorting faster — the increase in sorting speed is particularly significant when the table cells contain many DOM nodes but sorting is based only on the text content of the cell. If the content of the table is altered dynamically, the internal model is no longer correct. To fix this, the update function can be called to update the internal model of the table.
There are three options for calling the update function. The simplest is to call it just before sorting, but this is inefficient as the table may not have changed. The second option is to keep track of changes and call the update function just before sorting if changes have been made. The third option is to call the update function every time changes are made — this is the best technique if changes are infrequent as it means sorts can be performed without waiting for an update (which may take significant time for very large tables) but it does require developers to synchronise their code so that sorts are not performed in the middle of an update.