Switch_off Switch_on Switch_off
Inventive Labs: Web Problem Solvers

Sortable Tables for Prototype [19072007]

We've used Stuart Langridge's original JavaScript library for sorting tables on a number of projects. As perhaps the first important application of unobtrusive JavaScript techniques, it was a ground-breaking piece of code. But four or five years on, its ~480 lines of code were beginning to look a little hoary. Stuart has recently updated it with a more modern approach, but I still baulk at 20kb of JS for what is often a non-essential UI feature.

Since we use Prototype on most projects, my ideal was a slimmed-down implementation of sortable tables that leveraged Prototype to gain some efficiency and concision. Out of long habit I began with a Google search to see if anything had already been done — after all, we're inventors, not re-inventors. I found Inigo Surguy's impressively brief implementation, developed during a pedagogical analysis of recent developments in JavaScript.

Testing it out, I had a few issues with it — it was quite slow, it required markup that I considered unnecessarily verbose, it relied on a superfluous logging library, and there was some potential for namespace clashes when let loose amongst other JS (init() is a pretty common function name). There was also a function or two that duplicated Prototype functionality. And, as a purely personal aesthetic preference, I like my JavaScript to be OOP and mindful of 80 character line limits.

So I ended up borrowing Inigo's useful approach to the problem and rewriting the code mostly from scratch. This implementation resolves the issues listed above and does some caching of comparison data to gain a little speed. Also, it's 4kb. Download it:

Sortable Tables for Prototype

Like Inigo's version, this is released under the Creative Commons Attribution-ShareAlike 2.5 license.

Here's a simple demo. Click the headings to re-sort the table:

ID Inventor Price Expires
1 Thomas Edison $13.50 13 Feb 2008
2 Nikolai Tesla $21.00 4 Aug 2007
3 James Harrison $13.27 25 Dec 2007




* Obviously, this may not work within your feed reader.



Chris Waters [Fri 10 Aug 2007, 5:39AM] said:

This is nice, but it keeps pages from validating due to the sort attribute in the header cells. Is there anyway to get sortable columns and validation?

Joseph [Tue 14 Aug 2007, 2:36PM] said:

It shouldn't be too difficult to modify the script to move the sort declarations into the class attribute which you could parse to read out their values.

There's obviously two sides to the argument regarding custom attributes and XHTML validation. I come down in favour of custom attributes, particularly when you're looking for key/value pairs (and would thus have to write classnames like "foo=5"). Muddying up both your XHTML and your Javascript in order to sneak under the radar of validation just seems backwards to me.

Of course, using the class attribute for behavioural flags is still quite reasonable — indeed, it fits within the general concept of a "class".

Yubris [Tue 21 Aug 2007, 12:38PM] said:

404'ed!

The requested URL /static/files/assets/2227/sorttable.js was not found on this server.

Joseph [Tue 21 Aug 2007, 12:50PM] said:

Thanks Yubris — the link (and the demo) works again.

James [Wed 2 Apr 2008, 2:10AM] said:

@chris, @joseph:

One idea would be to use the abbr or title attribute as the possible sort key to make it validate? Seems like most (all?) user agents dont do anything with these valid attributes (that accept regular text) when rendering TDs.

James [Wed 2 Apr 2008, 3:31AM] said:

i made the following changes to conform to validation:

1) replace 'sort' with 'axis' on line 84:

var sortFn = this.compareFunction(th.getAttribute('axis'));

2) in your html table, change any <th sort='date'> with <th axis='date'> (this will validate). Obviously the sort format could be any of [date|integer|float|caseSensitive] as per the sortable.js spec.

3) add a check for abbr attribute, whose presence in a td take precedence over the regular cell text contents (line 107):

getText:function(e){return e.text = e.text||e.getAttribute('abbr')||e.textContent||e.innerText||''},

4) in your html table, add the appropriate sortable information in the abbr attribute, eg:

<table>
<thead>
<th>Day<th>
</thead>
<tbody>
<tr><td abbr="20080401000000">
April Fools</td></tr>
<tr><td abbr="20080402000000">
Second of April</td></tr>
<tr><td abbr="20080402000000">
Third of April</td></tr>

</tbody>
</table>
James [Wed 2 Apr 2008, 3:35AM] said:

Thanks very much joseph, This is another case of "Ask google and you shall receive."

PS: my table above has errors, i know, but you get the idea :)

cross [Wed 21 May 2008, 8:59PM] said:

Great idea. Right what I need for a new project.

Will try to use this solution.

Sebastien [Wed 10 Sep 2008, 10:37PM] said:

As bandwith is one of my obsession, I was looking for a slim script to sort table. In the firsts google results, I found this one http://yoast.com/articles/sortable-table/ The weight is 8kb As the project I'm working on is using prototype, I said to my self: "maybe I can find a slimmer version using protoype". Then I found this page. Congratulation: from 420 lines to less than 100 lines respecting 80 characters/line, you did a great job!

Sebastian [Tue 16 Sep 2008, 6:42PM] said:

Nice script indeed, tiny and very usefull. I like it! I wanted some rows to be not sortable by specifying sort="none" so I modified the this.headers.each(function(th) part to look like this:

if(th.getAttribute('sort') != 'none')
{
  var span = $(document.createElement('span'));
  $A(th.childNodes).each(function(c) { span.appendChild(c); });
  th.appendChild(span);
  span.onclick = function () { me.sortOnColumn(th, span) }
}

Sebastian [Wed 17 Sep 2008, 2:56AM] said:

Oh yea, and also to sort positive or negative floating point values change return parseFloat(a.replace(/^.?([\d.]+).$/,"$1")) to return parseFloat(a.replace(/^.?([-\d.]+).$/,"$1"))

Sebastien [Tue 28 Oct 2008, 5:55AM] said:

Avoiding memory leaks with this script
I found out that this script produce some memory leaks, at least in IE 6. After reading this page, I put

div = null;

right after the line 41:

div.onclick = function () { me.sortOnColumn(th, div) };

and memory leak is gone!

Jesse Swensen [Tue 6 Jan 2009, 5:37AM] said:

Could you post your final version with the above changes?

Boban [Wed 8 Dec 2010, 3:03AM] said:

Good job I like it! Btw, is not NIKOLAI TESLA it’s Nikola Tesla

Only the comment field is required. Omitting the ID fields increases your risk of being mistaken for spam.

Preview or