Sorttable v2: making your tables even more sortable

Sorttable, the JavaScript table sorting library, is pretty much the most popular thing I’ve ever written. (Top hit for “javascript sort table” on Google, too.) Over the four years or so since I first released it, there’s been a steady trickle of thanks, feature requests, and bug fixes to it. I’ve finally got around to releasing a new version of the script that hopefully covers everything that people were looking for. You can get it at the same place as it ever was, sorttable: Make all your tables sortable.

What’s changed in version 2

The most important thing that’s changed is that sorttable now has a much much clever automatic column typer. You still can just drop sorttable in place and not have to do any configuration, but it’s quite a bit cleverer about working out whether your columns are numeric or dates or currency or text. It skips blank lines, it can tell the difference between English and American format dates, it understands numbers with commas in and negative numbers. This is the number one feature request.

Secondly, you can now use custom sort keys for those columns that sorttable can’t work out for itself. See the page for details, but this should allow anyone to make anything work with sorttable v2.

It’s also a bit more compliant with HTML standards. To add a “totals” row you should add the row to a <tfoot> section in your table. Sorttable v1 used a class of “sortbottom” on totals rows; for backwards compatibility this is still supported, but you really should be using <tfoot> instead.

In a similar way, sorttable now uses <thead> as your column headers if you have it. If you do not have it then it will create a <thead> and put the first row of your table in it. This is a backwards incompatible change: to apply style to your table headers, you should now style table.sortable thead, not table.sortable a.sortheader as in v1.

Input elements are now supported in table cells! If your table cells contain input elements then sorttable will use the value in the input element.

Sorttable is now quite a lot faster than it used to be, owing to various little tweaks. It’s especially fast at resorting the table by the column you’ve already sorted by (but reversed), because now it just reverses the table rather than doing the sort.

Stable sorting is supported but commented out in the code (because the stable sort is implemented in JavaScript, not using the native list sorter, and so it’s a lot slower). You can change this by editing one line in sorttable.js if stable sorting is important; see the page for details.

Thanks

Lots of people (really, really lots) have contributed code suggestions, feature requests, bug reports, and compliments about sorttable. Here’s my chance to say thankyou. So: thankyou to…

Eric Chang, Mehmet Kut, Dan Synder, Jeff Bradley, Eric Holstege, Victor Kryukov, Nikola Ivanov, Geoff Clevenger, Mikko Suniala, Scott Reynen, Justin Meyer, Leonardo Kenji Shikida, Ben Ostrowsky, Daniel Berlin, Richard Snazell, Mark James, Eric Rizzo, Garve, Andreas Rehm, Scott Kingdon, Marcus Månsson, Bill Barry, Michael Rumpler, Avi Rogers, Kevin Wu, Espen Hovlands, Petronel Laviniu Malutan, John M. Pierre, opus27, Brendan Bowles, Marty O’Brien, Alex Rubin, Chris Gay, Jack Vanhan, Guy Rosen, John Dawson, Ryan Korczykowski, Carl Forde, Pete K, Glenn Haser, Richard Grassy, Olivier Briat, Bob Hanson, Alex Z, Narayana Rao Kankipati, Rey Hernandez, Eric Moriztz, Marco Valk, Marcus Daniel, David Dockhorn, Angela Weise, Aneel Nazareth, Jeremy Hulford, Thomas K. Weinstock, Edward, Matthew Egbers, Anton Berezin, Moustafa Elqabbany, Justin Williams, Daniel Chace, Inigo Surguy, Vladimir Kornea, John Mund, Pablo, David Golden, Brad Kemper, Brian Schott, Christian Robottom Reis, Justin Haygood, C. David Eagle, Simon Willison, and Dean Edwards.

Phew! All those people have contacted me asking for new features or have sent me patches or have provided code that I was able to reuse in v2 of sorttable. Thankyou: for those of you who wanted sorttable to do something new, I hope you like it.

203 comments.

  1. Oh..you’re where I got that code from. Thanks!

  2. dsas: no problem. :)

  3. if i have more than one row in header, I want to do sort by the last header row, how can I set it?
    thx

  4. margiex: you can’t, I’m afraid. Sorttable doesn’t support tables with more than one header row, because it gets a bit confused by them.

  5. It would be nice if a third click on a header would revert the table back to the original sort, rather than just toggling ascending and descending on that column.

    Just a thought ;)

  6. mrben: daresay it would, but that would mean caching the table structure, which I’d like to avoid :) If you want that, hit refresh.

  7. Why would it mean caching the table structure? Surely you could define the default sort somewhere, and then re-run that particular sort on every third click of a header? Or have I over-simplified?

  8. mrben: there isn’t a “default sort”; there’s just “what the table looked like when it got served from the server”, which could be in any order at all or even no order.

  9. Ah. Point taken. Shame ;)

  10. mrben: hence “hit refresh” to get that order back.

  11. [...] Follow any comments here with the RSS feed for this post. Post a comment or leave a trackback: Trackback URL. « Discussion List, Crossdomain.xml forFlash [...]

  12. Would it be possible to add some extra variables to the makeSortable() function, like:

    makeSortable($(’table’), ‘header’, ‘ASC’);

    Where the last two can the name of the header and sorting order you’d like to use for sorting immediately instead of just adding the event listeners.

  13. tommie: Sorttable doesn’t support sorting the table as soon as the page is loaded. There are some notes as to why not in the old sorttable documentation (see “Sorting a table the first time the page is loaded”).

  14. In Netscape 8 this script close the window. There is a solution for this?

  15. Stuart: I’ve just had the inevitable “client-side sorting” request on a new project I’m working on. Less than 5 minutes later, we had it working. Thanks a lot for this script, I owe you a drink.

  16. Nice job! If I could only get it to work :(

    When I include your script file in my Asp.net AJAX site I get the following error.

    Error Sys.ArgumentTypeException: Object of type ‘Object’ cannot be converted to type ‘Array’
    Parametername:array

    This occurs even if I don’t have any sortables defined.

    Any Ideas?

    The error is occuring in a file calse ResourceScript.axd

    Here is the function

    Array.forEach = function Array$forEach(array, method, instance) {
    ///
    ///
    ///
    var e = Function._validateParams(arguments, [
    {name: "array", type: Array, elementMayBeNull: true},
    {name: "method", type: Function},
    {name: "instance", mayBeNull: true, optional: true}
    ]);
    if (e) throw e;

    for (var i = 0, l = array.length; i

  17. I’ve narrowed it down further and the code below in the sorttable init function is causing the error.

    forEach(document.getElementsByTagName(’table’), function(table) {

    if (table.className.search(/\bsortable\b/) != -1) {
    sorttable.makeSortable(table);
    }
    });

    I’m not as versed in Javascript as you are so any help would be appreciated.

  18. Got it working. It took 2 code changes. Basically it was erroring on function(table) and onsort it error on function(Cell). I’ve include my new code in case it helps someone else.
    // forEach(document.getElementsByTagName(’table’), function(table) {
    var tables = document.getElementsByTagName(”table”);
    for (var i=0; i

  19. Change 1
    var tables = document.getElementsByTagName(”table”);
    for (var i=0; i

  20. Sorry guys, this forum keeps cutting off my post when I include the code.

    I basically changed each foreach loop into an index loop and accessed each table and cell using the appropriate array index.

    I also had the problem that my tables are loaded via AJAX after page initialization. A simple call to sorttable.makeSortable(MyNewTable) worked like a charm.

    Thanks again for the code!

    Scott

  21. GaryF: that’s what it’s for. :)

  22. ScottW: glad you got it sorted! I’d like to talk over this in more detail; could you drop me a mail? (See the contact link for my address.)

  23. you are very appreciated for you good job at sorttable.js.
    And i also have a question.
    To have the function ” when the table is loaded, one column is sorted”, how can i do it?

    thanks very much!
    RobertLee
    From Peking of China

  24. Hey, I was tryin out the script, great job :) although having a few a problems, I think it is similar to ScottW’s problem, if you could somehow please provide me with the fix, I would be really thankful. I dont know if this is another problem when your table is in a javascript variable, and calling the html contents of the variable through innerHTML, but the script doesnt work on the tables then. (I think it works in IE, but not firefox and mozilla, really being odd like that)

  25. To Varun:
    I have used sorttable.js. it does indeed work in IE.

  26. Fantastic tool, thanks so much!

    I’m curious why you chose to use the non-standard sorttable_customkey="2" rather than a class attribute? I’m loath to use invalid markup. ;)

    That said, I can see myself using this in many places, particularly at my workplace, a community college in British Columbia, Canada. I’ve been creating complicated workarounds in my custom CMS but this is a far better solution all around. Well done!

  27. Jason: two reasons. Firstly, a custom sortkey is emphatically not a class :) I feel a bit guilty about using class atrributes for things like column type overrides, but they are *sort of* appropriate. If you use a class of “2″ as a sortkey, then you’re suggesting that that table cell is like other cells with a class “2″, which it ain’t; it contains (something that maps to) the value 2, which is not the same thing. That’s the academic ivory-tower argument. The other argument is that if you’ve got more than one class applied to the cell then it won’t know which one to use as the sortkey, and setting class=”sorttable_sortkey_2″ seemed very silly :) I didn’t like the invalid markup either, I have to admit it, but it seemed the lesser of the evils.

  28. Fair enough. I’m working tangentially with Moodle that does all sorts of your second example to attempt to be fully compliant. I admit it’s a bit crazy to look at class="course_47 subsection_cheese_danish_12". I think I’d still prefer that, but I definitely see your point.

    Nevertheless, I sure appreciate the code. :)

  29. I was wondering if there is any way to have the table sorted (instead of default) onload

  30. Thank you so much for your script! Is there anyway to have the script ignore strings that start with “the”, “a”, and “an” when sorting? I have a list of movie titles, and it would be great if the sort ignored these words. I can use the custom sort keys, but it would be great if the script did this automatically. Thanks!

  31. Rhonda: it’s not possible to do that easily, I’m afraid. I’d recommend using the custom keys to get this; I won’t make sorttable do it automatically because some people may want A or The to be included.

  32. FYI, I noticed there were some lines that included a conditional statement to use font face ="webdings" for IE. There seems to be semicolon missing after the & nbsp. I also had some trouble with some Windows boxes that didn’t have webdings installed, so I replaced them with images (ie only). I’ll try to put the code in below.

    original code:
    sortfwdind.innerHTML = stIsIE ? '& nbsp<font face="webdings">6</font>' : '& nbsp;& #x25BE;';

    my replacement:
    sortfwdind.innerHTML = stIsIE ? '& nbsp;<img src=\'res/i/interface/arrow-down.gif\' alt=\'\' />' : '& nbsp;& #x25BE;';

  33. (please note that I added spaces to the above comment; they shouldn’t be included in the original js, of course.)

  34. How can i get default sort on particular column on page load?

  35. Is there a quick way to change the color of the column that you are sorting?

    This would be very usefull for big tables.

  36. My application uses dates in the form ‘Jan 1, 2007′. Be default, sorttable treats this as alpha. I’ve managed to override this in my page with class=”sorttable_mmdd” which seems to sort chronologically instead and I thought this fixed my problem. The problem arrises when there are blank values in the list however. Instead of having all the blank values go to the beginning like I would have expected (and how the alpha and date sorts work), there are various dispersed blank values in the list. Is this a bug? Any suggestions would be welcome.

    Thanks.

  37. Scott: I advise you, in that situation, to use custom sortkeys. Instead of

    <td>Mar 1, 2007</td>
    <td></td>

    use

    <td sorttable_customkey=”20070301″>Mar 1,2007</td>
    <td></td>

    and then sorttable will happily sort them all correctly.

  38. My dates are being pulled from a database. How do I set up these custom keys when the output is variable? I’d need to translate 356 possible values. Many of these fields have timestamps as well. I’m not sure if what I’m trying to do is possible with this utility.
    Thanks.

  39. Scott: is you data stored in the database as the string “May 02 2007″, or is it stored as a date which you then format in the output? Most languages have something that will let you output ISO date format, which is designed for this sort of thing. Failing that, if sorttable isn’t good enough then don’t let m eprevent you writing your own, of course.

  40. I really like this. I was using v1 for some time and just happened to come back here (to look up something) and see v2 was put up. Great!

    One question; if the table (which is querie’d from a db) has no rows, i get some javascript errors. I tried to fix this myself, but got into hot water quite quickly. Not that javascript errors are terrible perse; but I know people around my company will come telling me about them.

  41. jimbo: hrm. I may patch sorttable to cope with this, but to be honest the answer to “sorttable doesn’t sort a table with no rows” is “don’t do that, then”, I think ;-)

  42. heheh, well, i do agree.

    of course, my data is coming from a mysql query, so i don’t really know how many rows are getting returned. of course, i guess i could just not display the table at all if there are no rows to display.

    hmmm.. not sure why i didn’t think of that before, actually. i guess i’ll do that.

    thanks. i really like this…

  43. I realize that you don’t support any ’sort on load’ function. I get lots of requests to restore a particular sort order when a page is loaded / refreshed though. In an ideal world I would create a cookie whenever a header is clicked and look for that when a page is loaded and sort accordingly. That would make my life much easier than having to pass a special ‘order by’ query value back each time.

    Just my $0.02.

    Thanks for the excellent script.

  44. My solution to the “sort dates with blanks” problem: (line 271)

    sort_ddmm: function(a,b) {
    mtch = a[0].match(sorttable.DATE_RE);
    if(mtch==null) {dt1=0};
    else { y = mtch[3];

    Regards

  45. Is there a quick way to change the color of the column that you are sorting?

    This would be very usefull for big tables.

  46. jimbo, I use a function to check if there are rows come back from the db, if not I display a row, in the 1st column that says No Results. This will tell the user there is nothing, rather than just leaving it empty, and also solves your problem

    Sydney

  47. I have a table with styles which shows odd rows with one colour and even rows with another. The problem comes up when I sort the table, then styles keep in the same row and the table is shown with unordered colours. Please, let me know if you have a solution for this.

    Madrid, Spain

  48. A good way to deal with alternating rows is to use a modulo in the Append Child area. (There are two locations, the 2nd is for reversing the sort)

    Search for tb.appendChild(row_array[j][1]); and tbody.appendChild(newrows[i]); and add the follow above them (make sure to stay inside the for loop)

    if(j % 2)
    row_array[j][1].className = “tRowA”;
    else
    row_array[j][1].className = “tRowB”;

    – and –

    if(i % 2)
    newrows[i].className = “tRowB”;
    else
    newrows[i].className = “tRowA”;

    Note: You hafto swap the order in the second function.

  49. Hi there, Is there a solution for begin the sort in a particular row?, for example I have other kind of information in the first row, and the header begin in the second row, I’ve tried to fix it but I dont found the solution…

  50. Hi,

    Love the script as it’s saved me a whole load of grief! I think I might have found a small bug though :-( When there is more than a single table on the page, say tables A and B, and each has columns, say 1, 2 & 3, when alternate table headers are clicked for sorting, with the third click on the same as the first header to reverse, I get an error on page and the sorting arrow appears in the wrong table. Using the table notation this would be:

    click B1/2/3 -> click A1 = Error>>.

    Does this relate at all to ScottW’s posts?

    Thanks

    Rich

  51. submission seems to have shredded part of the post

    order is A1 then B1/2/3 then A1 = Error

  52. When I attempt to use more than one table I am having the same issue as Rich G . The browser displays an “invalid argument” message. Debugging shows that this is being thrown from on of the following code segments depending upon the sort: this.removeChild(document.getElementById(’sortable_sortrevind)); and this.removeChild(document.getElementById(’sortable_sortfwdind));

  53. Nice to know I haven’t gone mad ;-)

    I’ve come to the conclusion this is because the element found by document.getElementById does not have to be part of the same table as the calling cell and hence cannot be removed from its children in this case.

    I’m now working out how to ensure that: 
    a: the element name is unique and known (or work outable) per table.
    b: only the cell’s siblings are searched and have the element removed as I want the sorting indicator to be possible on each table.

    Any thoughts?

    Cheers!

  54. Yes, more than one table on a page is broken, because I’m a bit of an idiot. It’s on the list for sorttable 3.

  55. Hey Rich G – I have to switch to another project for the next couple of days. If you come up with some possible ideas or dead-ends can you post them? If I can find some time, I will do the same. Thanks!

  56. Hi,
    Have a solution to this, the logic behind it is that the search by id is not necessary if the table head element is searched for children of a new sort_span type and any existing ones stripped. This ensures that the spans that have the arrows are removed for that table only.
    I’ve taken the liberty of using the same forEach method for the three cases for clarity.
    Hope that is all clear ;-)
    Changed code is:

              dean_addEvent(headrow[i],”click”, function(e) {

              if (this.className.search(/\bsorttable_sorted\b/) != -1) {
                // if we’re already sorted by this column, just 
                // reverse the table, which is quicker
                sorttable.reverse(this.sorttable_tbody);
                this.className = this.className.replace(’sorttable_sorted’,
                                                        ’sorttable_sorted_reverse’);
                                                        
                //get the thead for this cell
                  theadrow = this.parentNode;
                  forEach(theadrow.childNodes, function(cell) {
                    if (cell.nodeType == 1) { // an element
                      //get the spans in each cell
                      theNodes = cell.getElementsByTagName(’sort_span’);    
                          //and remove them
                          for(var z = 0; z < theNodes.length; z++)
                          {
                              cell.removeChild(theNodes[z]);
                          }
                    }
                  });
                sortrevind = document.createElement(’sort_span’);
                //sortrevind.id = ”sorttable_sortrevind”;
                sortrevind.innerHTML = stIsIE ? ’&nbsp<font face=”webdings”>5</font>’ : ’&nbsp;▴’;
                this.appendChild(sortrevind);
                return;
              }
              if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
                // if we’re already sorted by this column in reverse, just 
                // re-reverse the table, which is quicker
                sorttable.reverse(this.sorttable_tbody);
                this.className = this.className.replace(’sorttable_sorted_reverse’,
                                                        ’sorttable_sorted’);
                //get the thead for this cell
                     theadrow = this.parentNode;
                  forEach(theadrow.childNodes, function(cell) {
                    if (cell.nodeType == 1) { // an element
                      //get the spans in each cell
                      theNodes = cell.getElementsByTagName(’sort_span’);    
                          //and remove them
                          for(var z = 0; z < theNodes.length; z++)
                          {
                              cell.removeChild(theNodes[z]);
                          }
                    }
                  });
                sortfwdind = document.createElement(’sort_span’);
                //sortfwdind.id = ”sorttable_sortfwdind”;
                sortfwdind.innerHTML = stIsIE ? ’&nbsp<font face=”webdings”>6</font>’ : ’&nbsp;▾’;
                this.appendChild(sortfwdind);
                return;
              }
              
              // remove sorttable_sorted classes
              theadrow = this.parentNode;
              forEach(theadrow.childNodes, function(cell) {
                if (cell.nodeType == 1) { // an element
                  cell.className = cell.className.replace(’sorttable_sorted_reverse’,”);
                  cell.className = cell.className.replace(’sorttable_sorted’,”);
                  //get the spans in each cell
                  theNodes = cell.getElementsByTagName(’sort_span’);    
                      //and remove them
                      for(var z = 0; z < theNodes.length; z++)
                      {
                          cell.removeChild(theNodes[z]);
                      }
                }
              });

              this.className += ’ sorttable_sorted’;
              sortfwdind = document.createElement(’sort_span’);
              sortfwdind.id = ”sorttable_sortfwdind”;
              
              sortfwdind.innerHTML = stIsIE ? ’&nbsp<font face=”webdings”>6</font>’ : ’&nbsp;▾’;
              this.appendChild(sortfwdind);

  57. just realised that the last

    sortfwdind.id = ”sorttable_sortfwdind”;

    should have been commented out

  58. Also fixed/tweaked the code for alternate table row styling in the reverse function suggected by Johnny Moon, as this didn’t take into account the fact that the mod of the last row number (and hence the first row) for the reversed table was not the same as the mod of the first row in the normal table if there were an even number of rows, which meant that the styling would be swapped on the first reverse sort click for the row and this would persist until another column was chosen for sorting or the page refreshed, a very minor bug but visually distracting. The fix checks whether the table has an odd or even number of lines and then allocates styling accordingly, note that only the reverse function was affected by this:

    for (var i=newrows.length-1; i>=0; i–) {

    //begin inserted statement

    if(i % 2)

    {

    if(newrows.length % 2) //odd number of rows so start with tRowB

    newrows[i].className = (’tRowB’);

    else

    newrows[i].className = (’tRowA’);

    }

    else

    {

    if(newrows.length % 2) //odd number of rows so start with tRowA

    newrows[i].className = (’tRowA’);

    else

    newrows[i].className = (’tRowB’);

    }

    //end of inserted statement//

    tbody.appendChild(newrows[i]);

  59. Thanks Rich G!

  60. A bug in IE 6 causes a security warning when loading the script over https

    A fix is to replace this line:
    document.write(”<script id=__ie_onload defer src=javascript:void(0)><\/script>”);

    With:
    document.write(”<script id=__ie_onload defer src=’dummy.html’><\/script>”);

    The bug is documented all over the place.  The html page given doesn’t even need to exist.

    —Alex

  61. Ah thanks Alex I ran into that one last night and was about to look for a solution today and hey presto…

  62. Any plans to add scrollability to the code? Ideally, headers and footer stay fixed, body is scrollable. We have the first part worked out (IE6), but not the second.

  63. Jett: I’m not planning on adding that to sorttable; it’s just for sorting tables. http://www.imaputz.com/cssStuff/bulletVersion.html might be useful.

  64. In V2, how do I change the initial defualt sort direction from ascending to descending?

    Thanks!

  65. Mike: this requires editing sorttable.js. After the line:

    row_array.sort(this.sorttable_sortfunction);

    add a new line:

    row_array.reverse();

    Let me know if this works.

  66. Beautiful! That did work! Thank you very much for all the help, you do excellent work!

    Mike

  67. Hi Stuart,

    Just to say thanks for making the code available to everyone, it saved me quite some time from writing my own.

    Thanks again,

    Dan

  68. Hi everyone, hi Rich G!
    You said you fixed the problem with multiple tables, but I really don’t know where to place the code you posted a few days ago. Could you be as kind as to post your full working code (or a link to it) here? I’d be very thankful!
    mark

  69. Hi mark,

    It replaces the dean_addEvent part of the

    existing makeSortable: function(table) function and starts from about line 93ish in my editor, the rest of the code is unchanged so I wont bother clogging up the rest of this page with it ;-)

    Let me know if you have any further probs

    Rich G

  70. Hi Rich,
    Thank you very much for your help! I%27ve finally got it!!
    I always just looked at the bottom of the source where the dean_addEvent() function is defined…
    Thanks for fixing this multiple table problem. It was quite important for me!

  71. No worries it solved quite a few probs for me too, and I only really tweaked the stuff that was already there, which made my life a whole lot easier ;-)

    BTW just got the spam blocking maths question wrong which is a little worrying :-(

  72. Here’s a kludge for ’sort on load’:

    <body onload=’loader();>

    function loader()
    {
    if (!document.all)
    {
    var fireOnThis = document.getElementById(’TH id value’);
    var evObj = document.createEvent(’MouseEvents’);
    evObj.initEvent( ‘click’, true, true );
    fireOnThis.dispatchEvent(evObj);
    }
    else
    {
    var fireOnThis = document.getElementById(’TH id value’);
    fireOnThis.fireEvent(”onclick”);
    }
    }

    now put some unique ‘id=’ value in the <th> element for the column that you want to have sorted when the page loads. This works with FF and IE7.

  73. Great script! One question though.. Would it be possible to sort rows in pairs? Essentially, i have the following structure:

    tr > td.price , td.date, td.blah
    tr > td.description
    .. repeat

    Unfortunately I need two rows to fit all of the information about one product, but this creates a number of problems when trying to sort the table – namely, the second row gets all out of order, any ideas, suggestions?

    Best,
    Ilya

  74. Ilya: sorttable won’t do that; it’d need some fairly hefty modifications to the script, I’m afraid.

  75. Great great code! Many thanks!

  76. I just added this script to my 3D game comparison table but the script seriously screws the table up. I’d like to be able to sort by game name (top row) and feature (first, middle, and last columns). Any ideas? The table is very complex with nested col/row spans.

  77. eep2: sorttable can’t handle tables with colspans or rowspans, because working out how to sort a table like that is pretty close to impossible without knowing the details of the table.

  78. Well, how else to know the details of the table than to analyze the table prior to sorting?

  79. perhaps the best way would be to rethink the table structure :-(

    I’ve had a look at your page and it looks interesting but hard to follow from a first encounter (ie without knowing the background as to why you chose to do it that particular way)

    How is your table populated? Manually or via a db?

  80. Manually. I chose the layout (with the games across the top) because that reduces how much horizontal scrolling is necessary (since vertical scrolling is more common and easier). I tried to get it into a database but it’s just too complicated for me (not being much of a programmer)–check the main page and news/updates for more info. I’d be happy just to use a flat-file system with some kind of character-delimited list that PHP can sort and tabularize (allowing x games and x features/sections to be displayed only, etc), too.

  81. Sorry, the introduction was unreadable for me due to the colour scheme and font size :-( (and that’s on a 24″ widescreen at 1920 x 1200)

  82. Er, so increase the text size in your web browser and override the colors if you don’t like them…

  83. Sorry, inaccessibility of content is one of my pet hates, if i can’t read it I’m already browsing away

  84. just realised that sounded very critical of your site sorry, it wasn’t personal, I was just trying to explain why I rarely bother resetting my system to cope with a specific designers decision, have a look at sites such as http://www.csszengarden.com to see what clear and accessible design can achieve, its a good principle to design so that everyone can view your site rather than having to change their browser settings,

  85. So where’s the option on that site to have a dark layout? I don’t like bright white–it hurts my eyes… If I knew how to set cookies and allow people to choose/design their own color scheme, I would, but I don’t.

  86. in the zen garden each scheme has a different layout but the same content (supplied by the site), its an exercise in separating style from content and allows you to see what layouts you like and what you don’t, you may well have a valid reason for choosing your scheme I was merely commenting that it’s very hard to read ;-)

    You could use alternative stylesheets to have a selector for viewing your site as white on black or black on white for example or completely change the layout for people with rotated widescreen monitors, css is both fun and amazingly irritating to play with!

    to get slightly back towards the original start of our discussion, you could make your table into xml and then style that using css thus making it easy to add new content (by changing the xml only) or new layouts (by changing the css only) it might conceivably help your sorting table layout issues too!

    Hopefully I’m being slightly helpful and you don’t feel too criticised by my random thoughts ;-)

  87. test

  88. Dunno why my comments aren’t being posted (aside from short ones–assuming this one will work). This is the third time now…

  89. Need a way to edit/delete comments…

  90. Blah…my last comment didn’t show up, for some reason (maybe cuz I had “a href” HTML links in it. Anyway, I had the thought of doing CSS hiding via this script (minus the animation) but I’m not sure if it works with tables (without them having to be separate tables per game, which defeats the purpose of having multiple games in a single table to compare, in the first place).

  91. But then there’s this sortable table script which has a filter, which might be configurable as a checkbox above each column/game field (and perhaps even each row/feature) to hide/show it. I don’t know XML but maybe HTML+CSS+Javascript will suffice.

  92. Oh and there’s a stylesheet switcher that I’ll look into adding to my site(s).

    Anyway, thanks for the replies.

    (OK, one link per comment is stupid…)

  93. They got moderated, which is why they didn’t show up. The one-link-per-comment thing is Wordpress, not me specifically, but the huge majority of comments I get with more than one link in are spam…

  94. if you know the column class in a table you can hide the entire column and the same for rows so you could have a separate class for each game and switch them on or off as you like

  95. But is that only for columns that don’t span multiple rows (and vice versa)? Cuz, ideally, I’d like to consolidate cells that have the same content (developer, “yes”, “no”, etc)…

  96. I’m taking rubbish of course! there is no concept of a column in a html table definition, just rows and cells (hangs head in shame). Styling rows with a unique css class will allow easy turning on and off but doing this by hand will become a bit more tedious each time you add stuff and for columns like you have with multiple cell spanning, you would have to know something like each cell location in the parent row -> child cells tree and to find this you would have the same problem as what you have already encountered :-(

    I think for a table like this it might be easier to have the duplication for the sake of easier coding as you would be able to rely on knowing the same number of cells per row etc.

    I would do it in ASPX myself and so would avoid the problem entirely by generating the table on the fly each time things were clicked on but that might be using a sledgehammer to avoid the nut!

    Hmm I might have just talked you back to where you were a few days ago :-( sorry!

  97. Of course there’s a column concept in HTML tables, otherwise there wouldn’t be a col element and colspan attribute, for one. For two, there’s a colgroup element. I don’t know ASPX (whatever that is) either. I’m looking into various content management systems but am not having much luck (trying Drupal right now–I’d post a link but stupid WordPress is too paranoid about “spam links” ). Anyway, I’m more informed than I was a few days ago but still pretty much stuck on what to do and how to implement it.

  98. I’ve learn’t something new too, never come across col attribute before, will have a play could be very useful!

    ASPX is basically dynamic server side generated webpages ie you code how you want to generate the page and when the user browses to it the page is generated for them.

  99. Right…more coding…blech.

  100. you know you enjoy it really, join us on the dark side:

    “Don’t be so proud of this technological terror you’ve created. The ability to destroy a planet is insignificant next to the power of the force.”

    - Darth Vader

  101. Patch for stable sort :

    sort_alpha: function(a,b) {
      if (a[0]<b[0]) return -1;
      if (a[0]>b[0]) return 1;
      // when equals keep previous order (=row index)
      if (a[1].rowIndex<b[1].rowIndex) return -1;
      else return 1
    }

    Apply similar rule to sort_numeric, sort_ddmm, …

  102. Patch to show ’wait’ cursor while sorting :

    Insert this :
    dean_addEvent(headrow[i],”mouseover”, function(e) {
      this.style.cursor=’pointer’;
    });
    dean_addEvent(headrow[i],”mousedown”, function(e) {
      this.style.cursor=’wait’;
    });

    just before that :
    dean_addEvent(headrow[i],”click”, function(e) {

    });

    and add this line :
    this.style.cursor=’pointer’;

    before each return
    and after : delete row_array;
    in the same function

  103. I need a patch to sort single-digit dates (days, months, and even years) correctly, and not always in DD/MM/YY format either but MM/DD/YY, MM/D/YY, MM/D/Y, M/D/Y, M/DD/Y, etc.

  104. opus, what is “stable sort”?

  105. Hello? Anyone? Beuler, Beuler?

  106. That’s “Bueller”. You might get a patch if you asked a touch more nicely about it…

  107. Uh, how much more nicely can I ask “what is ’stable sort’”? Geez…too many damn overhypersensitive people online–I fucking swear it’s ridiculous!

  108. The definition is a google search away. The sorttable page itself links to the Wikipedia description of stable sorting.

    And I wasn’t talking about stable sorting, anyway, I was talking about you just saying “I need a patch to do X, Y, and Z”.

  109. Er, it’s not like I wrote “I demand a patch NOW!*($#” or something… I was being quite neutral about it, actually. Besides, why should I need to ask nicely for something that the script should already be able to do inherently? <buh-link> Anyway, stable sorting isn’t what I need…

  110. Single-digit date handling is on the list for sorttable v3.

  111. “Besides, why should I need to ask nicely for something that the script should already be able to do inherently?”

    Well thats how to win friends!

    “Anyway, stable sorting isn’t what I need…”

    Nope, quite right, what you need is to look through the code and fix it then share the fix with everyone else.

  112. Wondering if anybody has used sortable with checkboxes. I have a table with a column of checkboxes and labels set to sorttable_nosort. If I sort the table, check some boxes and submit the form, all the form elements get passed except for the checked boxes. If I submit the form without sorting the table,everything works as expected.

    Any ideas?

  113. Mark G: you’re not the first person to report this problem, but I’ve not been able to replicate it. Do you have a URL that demonstrates the problem? Which browser are you using?

  114. Mark G, All my table have checkboxes and work fine so I can’t say I’ve found a problem with it sorry :-(

  115. It’s an internal project so I don’t have a URL for you to look at.

    I’ve been able to replicate the problem on Firefox and Opera. It works fine on Safari.

    Thanks

  116. Thanks for the great script ! It help a lots.

    I have a minor problem, my table with 3 header rows (i understand it doesn’t work for this version) so I decided to change the script. But afetr some hard works, :o( I am wondering will I be able to achieve it ? 

    I change like:
    headrow = table.tHead.rows[table.tHead.rows.length - 1]

  117. (oops, sorry, haven’t finish my typing… )

    and make changes to row_array (to make it start from table.tbody, not counting the header…)

    Can I know am I in right direction ? or I am totally talking nonsense ?

    Thanks.

  118. EngDian: that’s certainly one approach to take. I haven’t yet decided how best to make sorttable support multiple header rows, which is why sorttable doesn’t do it yet. It’s planned for version 3.

  119. Sortable and AJAX.NET both has an Array.forEach function it’s just that they do not work the same way.
    To fix that just put a prefix before all the ForEach-functions in sorttable.js. Don’t forget to also change the 
    resolve.STforEach(object, block, context); // ST is the prefix
     in the base forEach function.
    ScottW has another solution above but I think this one might be simpler.

  120. Jonas: quite right, and added to the bug list.

  121. i would like to order the table by binding 2 row together

  122. Is there a way to skip a column from sorting?

    I have a first column with ranking (1 to whatever), and I want that to stay the same when sorting the table.

  123. Ryan: I’m afraid not. This is a known bug, though; see http://kryogenix.org/bugs/sorttable/left-hand-headers.html for details.

  124. Hi Stuart. Great code, very useful.

    I’m running into a problem using your sorttable v2 with BarelyFitz’s Tabber.js (http://www.barelyfitz.com/projects/tabber/), such that when I include a sorttable table, all tabs vanish (standard tabs w/cookies). When I use sorttable v1, it works fine. While I realize that its likely to be much to ask, I was wondering if you had any suggestions? (I’ve tried the prefix fix mentioned above to no avail)

    Also, does anyone have any advice for sorting a street address field, already merged into one field of Street # + Street Name? (where not all properties have a #?)

    Thanks a lot!

  125. Sadly, sorttable doesn’t seem to work if your doctype is XHTML 1.0 versus HTML 4.01. If you do upgrade the library, let me know!

  126. Kathy: that’s not supposed to happen. Do you have an example of a page that it doesn’t work on, so I can test? Feel free to contact me by email if you prefer.

  127. josh: have you got a page that exhibits the problem, so I can take a look?

    For sorting oddly-formatted fields, you’ll want to use sorttable’s custom sort keys.

  128. I spent some time searching for a solution to this until I came back and reread the whole thread. The bugfix link isn’t by the error message tha caused it.

    sys.argumenttypeexception object of type object cannot be converted to type array

    http://kryogenix.org/bugs/sorttable/foreach-collide.html

    I fixed mine by doing a replace on forEach to STforEach

  129. Your script doesn’t work on IE7.
    Great with FF2.

    As an exemple, you tables on this page are not active with IE7 but are on FF2.

    Chears,

  130. Fabrice: oops. Added to my bug list. Thanks.

  131. Thanks for the script. I use it at work for sorting off of an
    Indexing Server with ASP. Is there any way to manipulate the script to allow for date modified? Since this is a search I cant simply alter the cell. I need to sort in the format
    mm/dd/yyyy HH:MM:SS AM/PM

    Thanks again for sharing this great script!

  132. Jared: if you can’t use custom keys, then the script will need to be modified, as you mention. It can be done; you’ll need to edit the date-parsing functions and the date regular expression. If you want me to do it, contact me and we can talk about rates and so on.

  133. Here is a patch to make the sort stable.
    The modification is to set id to the original row index and sort by row.id when rows are equal (one drawback is that existing id:s on tr-elements are removed).
    The added code starts with ”+”:

        forEach(document.getElementsByTagName(’table’), function(table) {
          if (table.className.search(/\bsortable\b/) != -1) {
            sorttable.makeSortable(table);
    +        if (table.className.search(/\bstablesort\b/) != -1)
    +          sorttable.setrowids(table);
          }
        });
      },

    +  setrowids: function(table) {
    +    // Set id=rownumber, makes the sorting stable with the help of sort_by_id
    +    sortfn = sorttable.sort_alpha;
    +    for (var i=0; i<table.tBodies[0].rows.length; i++)
    +      table.tBodies[0].rows[i].id = i+100000;
    +  },

    +  sort_by_id: function(a,b) {
    +    if (a[1].id==b[1].id) return 0;
    +    if (a[1].id<b[1].id) return -1;
    +    return 1;
    +  },

      sort_numeric: function(a,b) {
        aa = parseFloat(a[0].replace(/[^0-9.-]/g,”));
        if (isNaN(aa)) aa = 0;
        bb = parseFloat(b[0].replace(/[^0-9.-]/g,”));
        if (isNaN(bb)) bb = 0;
    +    if (aa==bb)
    +      return sorttable.sort_by_id(a,b);
    +    else
          return aa-bb;
      },
      sort_alpha: function(a,b) {
        if (a[0]==b[0])
    +      return sorttable.sort_by_id(a,b);
        if (a[0]<b[0]) return -1;
        return 1;
      },

      sort_ddmm and sort_mmdd:
    +    if (dt1==dt2) return sorttable.sort_by_id(a,b);

  134. Niklas: what was wrong with http://www.kryogenix.org/code/browser/sorttable/#stablesort ?

  135. I sent you an email as requested about sorting mm/dd/yyyy hh:mm:ss AM/PM but I never heard back from you. Just wanted to make sure you got the message?

  136. Jared: sorry, replied now!

  137. > Niklas: what was wrong with http://www.kryogenix.org/code/browser/sorttable/#stablesort ?
    Differences:
    shaker_sort:
    * Uses custom sort function
    * multi-level sorting of data (when two rows are equal the previous sort order is used)
    My patch:
    * Uses JavaScript sort (sorting should be faster, but initial setup is slower)
    * When two rows are equal the original order is used
    * If you sort with sort_by_id, or on a column with all the same values, the result is the original order.
    So you could quite easily add a third state when clicking a third time on the column header – unsorted (i.e. remove the arrow and sort with sort_by_id)

    Note:
    To make my patch behave like shaker_sort (general way of making any sort stable):
    1. skip setrowids (not needed)
    2. add j as the third element in row_array
    for (var j=0; j<rows.length; j++)
    row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j], j];
    3. Modify the sort_by_id function (or replace all “sort_by_id” with “a[2] – b[2]“):
    sort_by_id: function(a,b) {
    return a[2] – b[2];
    },
    4. Use row_array.sort(this.sorttable_sortfunction); as normal
    Should give the same result (not tested though).

  138. hi great script!!

    i need to know how to do this:

    I have one column that I don’t want to be sorted at all, how do I do that? Thanks in advance!

  139. lau: see the documentation.

  140. Hi, just updated to v2. The speed increase is excellent.

    is there any documentation on any additional css stuff to interact with sortable.. I was thinking along the lines of a:hover.sortable but cant get anything to work.

    in v1 when you would hover over the heading the pointer would change… in v2 it doesn’t & it shows no obvious signs of being a “link” or sortable, or do I have mine incorrectly setup?

    many thanks

  141. gee: to style links in a sortable table, you want

    table.sortable a { styles }

    and to style your headers, use

    table.sortable th { cursor: hand; }

  142. Hi,

    Many thanks for the response.. I think I worded the question badly but it gave me some ideas for future use.

    just to check did you mean 
    table.sortable thead {}

    rather than 
    table.sortable th {}

    as I can’t get anything out of th

    ….
    what I have done though is this

    table.sortable thead {
        padding:3px;
        background-color:#52418C;
        color:white;
        font-weight: bold;
        text-decoration: none;
        height: 12.75pt;
        
    }

    table.sortable thead:hover { 
        text-decoration: underline;
        background:#A5DD29; 
        cursor: pointer; 
    }

    note pointer rather than hand as I found out hand don’t work in ff

    what happens isn’t exactly what I’d expect in that when you hover over one header cell is the whole header row changes colour & underlines… which makes me think I’ve got something wrong & it’s where ’th’ comes in?

    off to research css a bit more, but any pointers much appreciated.

  143. doh… th won’t work unless you use <th></th>

  144. gee: ah, yeah, you should be using th inside a thead :)

  145. Awesome script!! It works in IE7 with Tabber.js (which Josh reported) for me.

    I have a display problem however. When the column header string is shorter than its values in tbody, adding the unicode triangle when sorting on the header works great. See example below.

    Name

    Employee A

    Employee B

    But when the column header string is longer than any of its text in tbody, the added triangle increases the th length and messes up my table format. The right table border is gone, and the tbody formatting (background color) doesn’t apply to the increased thead/th length. For example,

    Name

    A

    B

    Can you give me some tips on how to work around this?

    Thanks!!!

  146. Hi, thanks for this script !

    I use striped-tables, and I see that is in the wish list.

    As I did not want to wait, I have to add this to script :

    1/ a new function

    striped: function(table){

    for (var i=0; i<table.tBodies[0].rows.length; i++) {

    table.tBodies[0].rows[i].style.backgroundColor=(i%2==0)?table.getAttribute(’R1BgColor’):table.getAttribute(’R2BgColor’);

    }

    },

    2/ I call it in init just before makeSortable

    sorttable.striped(table);

    sorttable.makeSortable(table);

    3/Another call before sort function

    delete row_array;

    sorttable.striped(this.sorttable_tbody.parentNode);

    4/ I add two attributes to the table

    Note: Class instead og Bgcolor would be better, I think.

    What are you thinking about this ?

  147. Martial: that’s certainly a good way to solve your specific problem, and I’m glad sorttable could help you!

  148. [...] have a sortable sub folder structure and sortable images per folder. Searching the web, I found an excellent javascript solution for sorting tables. The script works very well and I have adapted it for use in the Lazyest Gallery Manage page with [...]

  149. Is there any “onsorted” event that gets fired after a sort is complete? If not, any recommendation on how to add support for that? I need to make an Ajax call after a sort to store the new order on the server. I’m thinking it would be most convenient if I could just add an onsorted=”myjsfunc();” to the table.

    Thanks,
    Russ

  150. Thanx,
    It is a beautiful script works like charm in my scripts without much changes

  151. hey…
    i am trying to get sortable to work for textbox inputs…the values are entered dynamically each time for some further validations… the text i am entering is of a certain format eg. ‘PP_VER-RE_908′ the innerText code in the sorttable.js considers this as numeric…after that it just inverts the rows in the table…sort doesnt happen..any suggestions???

  152. Vinnie: what you’re talking about will, I think, require some custom (thus paid-for) enhancements to sorttable. Drop me an email (http;//www.kryogenix.org/contact) and we can talk about it.

  153. i need to know how to do this:

    I have one line not a column that I don’t want to be sorted at all (some ads), how do I do that? Thanks in advance!

  154. Bastien: if you mean that you’d like that column to stay in the same order even if the rest of the table is sorted, then that’s http://www.kryogenix.org/bugs/sorttable/left-hand-headers.html which is a known request for enhancement. I’m not sure when I’ll have time to get to it, though. (You can get it up my list with money: see http://www.kryogenix.org/code/browser/sorttable/#payforwork for details :))

  155. Oh my God! I can’t believe it! All that functionality and it took me 5 seconds to drop it in and it just works! AWESOME!!! You just saved me a ton of time in dinking with database query strings.. You are the man! THANK YOU!!!

    -Hatch in Costa Rica…

  156. Hatch: no problem Glad you liked the script. :)

  157. It seems I ran into a bug with the date format dd.mm.yy. At least the sorting does not work properly and I cannot figure out why. It sorts in a very weird way.
    You can see it at http://www.quaddicted.com/spmaps.html

    The script seems to loaded right as sorting the other columns works fine.
    Unfortunately I am rather “code-blind” so I can’t see why it does work so wrongly. Tried Firefox 2.0.0.14 and Opera.

  158. I love it, it’s da bomb.

    Is there any way to sort an image column? No, I don’t mean sort them by what they contain (!), just if there’s an icon there or not. For instance, if there’s a star for “Featured” something or other, and a camera icon for “Has a Photo”, etc. it would be nice to be able to just bring all these to the top.

    I know, I know, give ‘em an inch… ;^)

  159. ps: I mean besides inserting a number “1″ in front of the icons and giving them a css font size of 1 and a color the same as the background ;^) Because that works! (but it’s a little wacked)…

  160. Table Sorta Guy: add a custom sort key of 1 or 0 to the cells in question. See http://kryogenix.org/code/browser/sorttable/#customkeys for details.

  161. Awesome! Thank you !!!

  162. whatever

  163. I love this script, however, I have a checkbox that allows one to select certain records for processing via a post of the form information.

    I am trying to add an option to select or unselect all but I would like the select or unselect to select or unselect only visible rows, not all rows.

    Is there any easy way to do this that anyone knows of?

  164. Stephanie: I’m not sure what you mean by “visible” rows? Sorttable doesn’t make rows visible or invisible.

  165. Hi, more stuff:

    <pre>
    * Sort detect empty as lowest ”value”
    </pre>

    Great job - rgds. Henrik at Lassen dot dk

    Solutions proposed
    ==================
    <pre>
    //* Sort detect empty as lowest ”value”

      sort_numeric: function(a,b) {
        aa = parseFloat(a[0].replace(/[^0-9.-]/g,”"));
        bb = parseFloat(b[0].replace(/[^0-9.-]/g,”")); 
        return sorttable.sort_NaN(aa) - sorttable.sort_NaN(bb);
      },
    </pre>

  166. Hi, here is what i am looking for (resend):

    * Embed script (One page HTML)
    * Sort detect IP addresses

    Great job - great speed - rgds. Henrik at Lassen dot dk

    PS. Never understod the difference between ”Submit comment” and ”Post comment”

    Solutions proposed
    ==================
    //Embed script: Use double qoutes

    //Sort detect IP addresses
      if (text != ”") {
        if (text.match(/^(\d{1,3}\.){3}\d{1,3}$/))     return sorttable.sort_ip;
        if (text.match(/^-?[£$¤]?[\d,.]+%?$/    ))     return sorttable.sort_numeric;
      …
      sort_ip: function(a,b) { // Rgds HL
        aa = a[0].split(”.”); aaa = 0; for(i in aa) aaa = aaa*256+parseInt(aa[i]);
        bb = b[0].split(”.”); bbb = 0; for(i in bb) bbb = bbb*256+parseInt(bb[i]);
        return sorttable.sort_NaN(aaa) - sorttable.sort_NaN(bbb);
      },
      sort_NaN: function (a) { 
        if (isNaN(a)) return -Number.MAX_VALUE; return a;
      },

  167. I just wanted to submit my tweak to enable the correct sorting of negative numbers that are denoted by enclosing them in parenthesis like (10.39) = -10.39

    What I do is have it replace the opening parenth with a negative sign before stripping all other non-number chars.  That way it retains the negative and sorts in true numeric rather than as an absolute value when using parenths.

      sort_numeric: function(a,b) {
        aa = parseFloat(a[0].replace(/\(/g,’-').replace(/[^0-9.-]/g,”));
        if (isNaN(aa)) aa = 0;
        bb = parseFloat(b[0].replace(/\(/g,’-').replace(/[^0-9.-]/g,”));
        if (isNaN(bb)) bb = 0;
        return aa-bb;
      }

  168. Is there an equivalent to “sortbottom” that will keep a row at the top? (e.g. “sorttop”)

    Thanks.

  169. Jason: I’m afraid not. You’d need to make a custom enhancement to sorttable to do that (or talk to me about rates for custom JavaScript work by dropping me a mail).

  170. Hey! I’ve implemented this script but am having trouble getting it to work.

    http://phpfi.com/384613

    is my code,

    When I click on the header column titles an arrow comes, and if I repeatedly click it the arrow points up / down, but the column isnt actually sorting.. any idea why?

  171. Here’s a complete solution for the empty cell problem with dates. Thanks to Erich Bakx!

    Just add a check for each mtch-variable. After doing this it should look like the following code:

      sort_ddmm: function(a,b) {
        mtch = a[0].match(sorttable.DATE_RE);
        if(mtch==null) dt1=0;
        else {      
            y = mtch[3]; m = mtch[2]; d = mtch[1];
            if (m.length == 1) m = ’0′+m;
            if (d.length == 1) d = ’0′+d;
            dt1 = y+m+d;
        }
        mtch = b[0].match(sorttable.DATE_RE);
        if(mtch==null) dt2=0;
        else {       
            y = mtch[3]; m = mtch[2]; d = mtch[1];
            if (m.length == 1) m = ’0′+m;
            if (d.length == 1) d = ’0′+d;
            dt2 = y+m+d;
        }
        if (dt1==dt2) return 0;
        if (dt1<dt2) return -1;
        return 1;
      },
      sort_mmdd: function(a,b) {
        mtch = a[0].match(sorttable.DATE_RE);
        if(mtch==null) dt1=0;
        else {     
            y = mtch[3]; d = mtch[2]; m = mtch[1];
            if (m.length == 1) m = ’0′+m;
            if (d.length == 1) d = ’0′+d;
            dt1 = y+m+d;
        }
        mtch = b[0].match(sorttable.DATE_RE);
        if(mtch==null) dt2=0;
        else {        
            y = mtch[3]; d = mtch[2]; m = mtch[1];
            if (m.length == 1) m = ’0′+m;
            if (d.length == 1) d = ’0′+d;
            dt2 = y+m+d;
        }
        if (dt1==dt2) return 0;
        if (dt1<dt2) return -1;
        return 1;
      },

    Now the sort-functionality also works with dates and empty cells.

  172. I just came across the bug with https as described earlier. I tried the solution:
    A fix is to replace this line:
    document.write(””);

    With:
    document.write(””);
    but although the page loads securely – the table doesn’t sort any more!
    Am I missing something?

  173. while doing the following perl ( very parred down example to save space )
    #!/usr/bin/perl
    use CGI qw(:standard);
    $sy = 2009 ;
    $sm = ‘02′;
    $sd = 13 ;
    $st = ‘CIMIS’ ;
    print header;
    print start_html(-title=>”WeatherTRAK Climate Database Output”, -script=>{-src=>”sorttable.js”} );
    print ”;
    print “”;
    open(OUT, “/data/www/pgm-bin/ete_rpt $sy$sm$sd $st |”);
    while()
    {
    print $_;
    }
    close OUT;
    exit;

    I GET THE FOLLOWING ERROR
    [Thu Feb 19 03:01:17 2009] [error] [client 10.0.0.8] (8)Exec format error: exec of ‘/var/www/cgi-bin/sorttable.js’ failed, referer: http://10.0.0.240/cgi-bin/d1.psql
    [Thu Feb 19 03:01:17 2009] [error] [client 10.0.0.8] Premature end of script headers: sorttable.js, referer: http://10.0.0.240/cgi-bin/d1.psql

    yet if I redirect the perl to a file wiht the > and then use the web browser on that file it always works..
    IDEAS PLEASE ??

  174. DanD: you have sorttable.js in your cgi-bin folder, and Apache is therefore trying to execute it as a CGI, which doesn’t work. MOve it somewhere else.

  175. Hi there, great script works like a bomb. I was wondering how I can set the alternating row colors with sorttable. Is there a simple way to do this. thanks

  176. Articfox: currently there isn’t. This is a known issue (http://www.kryogenix.org/bugs/sorttable/striped-tables.html). If you’re interested in having it fixed and want to pay me to do it, drop me a line. :)

  177. Hi there, this is a really great script. I just had one uestion if i have alternating row colors how can i get them to stay alternating with this script cause mine colors stay with the sorteed data and the row colors get mixed up

  178. Hello,
    For the alternating table row styles, I copied the code provided by Johnny Moon as such:

    above tb.appendChild(row_array[j][1]); (within the for loop) I placed:

    tb.appendChild(row_array[j][1]);

    above tbody.appendChild(newrows[i]); (within the for loop) I placed (tweaked from Rich G):

    if(i % 2)
{
if(newrows.length % 2) //odd number of rows so start with tRowB
newrows[i].className = (’tRowB’);
else
newrows[i].className = (’tRowA’);
}
else
{
if(newrows.length % 2) //odd number of rows so start with tRowA
newrows[i].className = (’tRowA’);
else
newrows[i].className = (’tRowB’);
}


    This made the table sort not work for me. Did I do this correctly?

  179. Oop….correction to the above comment:

    above tb.appendChild(row_array[j][1]); (within the for loop) I placed:

    if(j % 2)
    
row_array[j][1].className = “tRowA”;
    
else
    
row_array[j][1].className = “tRowB”;

    above tbody.appendChild(newrows[i]); (within the for loop) I placed (tweaked from Rich G):

    if(i % 2)
    
{

    if(newrows.length % 2) //odd number of rows so start with tRowB
newrows[i].className = (’tRowB’);
    
else
    
newrows[i].className = (’tRowA’);

    }
    
else
    
{
if(newrows.length % 2) //odd number of rows so start with tRowA
newrows[i].className = (’tRowA’);
    
else
    
newrows[i].className = (’tRowB’);
    
}


  180. I trimmed down the fix to make alternating row styles down to a single added line (prefixed with + below). Hopefully this doesn’t get reformatted too much.

    tb = this.sorttable_tbody;
    for (var j=0; j<row_array.length; j++) {
    + row_array[j][1].className = j%2 ? “oddrow” : “evenrow”;
    tb.appendChild(row_array[j][1]);
    }

  181. You have reinforced my faith in human good nature (and skill). Thank you so much for putting your wonderful work in the public domain. It has saved me literally hours of menial work… and I probably would have indeed used a querystring and another call to SQL to generate a far less elegant solution to my problem.

    Actually, that would have been difficult because some of the columns were being generated from results from previous columns (which came from various sql tables, some incomplete)…

    Dude, you are a legend!

  182. Hello,

    Are you planning to include fix suggested by ScottW that prevents script working with asp.net ajax. I did and it looks like working.
    You would save some time to others.

    Thanks,
    Velja Radenkovic

  183. Velja: I can’t test that the fix works. I’m loath to include a fix that I myself haven’t tested. Besides, it’s in my bug list, which means it’s on my radar to fix.

  184. sil,

    You can’t test it? Yes you can. The fix is to replace foreach iteration with plain for loop and access the element of array using index.

    When I think better I think the problem is not in foreach iteration implementation but rather in ‘table’, ‘cell’ etc. variable names. Replacing iteration solved the problem because it eliminates variable named ‘table’ from js and uses tables[i] instead which is not in collision with asp.net ajax scripts.

    Generally speaking using table, cell, layer and similar as variable names is always bad idea in java script because it doesn’t have namespaces or packages or any other method of code separation.

    I have my piece of code working so don’t understand that I am pushing you because I need something. Its a good script and it works flawlessly with asp.net GridView. It would be a pity to discourage people from using it because of minor problem.

    Also alternating row colors is common thing in html tables and script doesn’t take care of that. That can be fixed easily too.

    Thanks,
    Velja

  185. Velja: no, no, I meant that I can’t test that it no longer breaks ASP.NET because I can’t run any ASP.NET sites.

    The whole forEach implementation is going away in sorttable v3 anyway.

  186. Simply great script, and very useful. Used it for a company in an effort to minimize load on servers where tables where retrieved and likely to be sorted on different fields. One modification I made to the script though, I will suggest. This minor mod has worked quite well and have found no errors yet. Since I live in Iceland and our character set is a bit different, e.g. we have letters like ‘á’, ‘ð’,'þ’ and script did not give correct results. So what I tried is this with the sort_alpha method:

    sort_alpha: function(a,b) {
    a[0]=a[0].toLowerCase();b[0]=b[0].toLowerCase();

    var regexp=/á/g;var regexp2=/ð/g;var regexp3=/é/g;var regexp4=/í/g;
    var regexp5=/ó/g;var regexp6=/ú/g;var regexp7=/ý/g;var regexp8=/æ/g;var regexp9=/ö/g;

    var regArray=new Array([regexp,'a{'],[regexp2,'d}'],[regexp3,'e~'],
    [regexp4,'i~'],[regexp5,'o¡'],[regexp6,'u¢'],[regexp7,'y£'],
    [regexp8,'þ¤'],[regexp9,'þ¥']);

    for ( var i=0; i<regArray.length; i++)
    {
    a[0]=a[0].replace(regArray[i][0],regArray[i][1]);
    b[0]=b[0].replace(regArray[i][0],regArray[i][1]);
    }

    if (a[0]==b[0]) return 0;
    if (a[0]<b[0]) return -1;
    return 1;
    },

    Also I made an extra function to sort the names since they are sorted by the first name and last, anything in between is less important. Like to hear what you think and any comments are appreciated. In all, great script that works well, thanks Stuart.

  187. OOps, sorry! I forgot to explain the idea. The ‘unique’ characters were replaced with others, e.g. ‘¤’ that are not likely to be part of any name. Then finally, is the sort used.

  188. Max: the best way to do that is to use localeCompare, as described in the outstanding bug report http://www.kryogenix.org/bugs/sorttable/non-english-chars.html which I plan to implement in sorttable v3.

  189. Ok. I did not know about this bug report. Thanks, you were quick with answers!

  190. [Tried emailing Stuart to no effect; here is the message]
    I have used your sorttable scripts on sites that I design and develop for The Nature Conservancy to good effect, and I thank you for making them available.

    In redoing one site, I have run into a problem in IE (6 and 7) on WinXP. I have not tested in Vista. This problem does *not* occur in FF or Safari or Google Chrome.

    In this new version, I have wrapped my sortable in a tag whose display is alternately “none” or “block” (Close/Open), controlled by another script. This does not affect the sort function in any browser or system besides IE. I have tested it now with the simplest possible show/hide script directly in the file head
    , with no luck, but I have the following observation (I think):

    (1) When I load the page into a new tab in IE, and Open the table, it does NOT sort
    (2) when I click on another page, then return to my page and Open the table, it DOES sort
    (3) Opening and Closing the table without reloading does not change the sortability
    (4) When I Reload the page without going elsewhere and returning, and Open the table, it does NOT sort

    [test and live site URLs deleted; please email me]
    Thanks for any help. I have several tables of this type.

  191. Great scripts. I got one problem. When my table uses and to specify the column widths, the sorting becomes very slow for a table with 600 rows. It is like 10 seconds vs. 2 seconds without colgroup.

    Can you shed some light if this is solvable?

    Thanks!

  192. (Sorry to post again. HTML tags in my previous post have been removed by the page)

    Great scripts. I got one problem. When my table uses tags “colgroup” and “col width=xx” to specify column widths, the sorting becomes very slow for a table with 600 rows. It is like 10 seconds vs. 2 seconds without colgroup.

    Can you shed some light if this is solvable?

    Thanks!

  193. Henry: cor, I’ve never tried that. Can you drop me a mail with more details and (ideally) a URL to an example?

  194. Wonderful scripts. It’s really helpful. I have one concern, I made a table inside a div that when query reaches 20 items, the div scrolls. But I want the table header to be excluded from the scrolling part so when the user scrolls down to the last item, the table head would still remain on top, that way the sorting would still be visible. How do i do that with your script?

    Thanks!

  195. Ryan: you should investigate http://www.imaputz.com/cssStuff/bigFourVersion.html.

  196. I made it! thanks…

  197. This is a great script! Very usable.

    FYI.

    I discovered that IE 6 & 7 does not like this script under SSL though. It complains that there are insecure items when using it.

    I have recently discovered that there is some detection of removeChild() as being erroneously detected as “unsafe”, but by replacing those with outerHTML=” it still detects this script as insecure.

    If anyone solves this issue (other than using a different browser ;) )

  198. Crispy: see http://www.kryogenix.org/bugs/sorttable/https-secure-content.html for a record of this bug and a possible workaround.

  199. Hi,

    Is it possible to make the small hand symbol appear each time we roll the mouse over the headers. Makes it more intuitive.

    Thanks! and great code !

  200. Seb:

    table.sortable th { cursor: hand; }

    in your CSS file.

  201. I was having a problem with IE7 on an XP machine. When the table headers were clicked to sort the rows, the entire table would disappear. In order to fix this problem I changed the behavior of sorttable.js to copy the table rows instead of reference the existing rows. Sorttable is great. I especially like the version 2 options to not sort some rows, and the custom sort keys.

    Here is the function to copy the rows.

    ,
    copyTableRow: function(tableRow) {
    var tr = document.createElement(’tr’);
    columns = tableRow.getElementsByTagName(’td’);
    for (var i=0; i<columns.length; i++) {
    var td = document.createElement(’td’);
    td.innerHTML = columns[i].innerHTML;
    if (columns[i].getAttribute(”sorttable_customkey”) != null) {
    td.setAttribute(”sorttable_customkey”,columns[i].getAttribute(”sorttable_customkey”));
    }
    tr.appendChild(td);
    }
    return tr;
    }

    ——

    I added it to the makeSortable function and reverse function…

    (In makeSortable, just before the shakersort option)
    for (var j=0; j<rows.length; j++) {
    var tr = sorttable.copyTableRow(rows[j]);
    row_array[j] = [sorttable.getInnerText(rows[j].cells[col]), tr];
    }

    (and the beginning of the amended reverse function)
    reverse: function(tbody) {
    // reverse the rows in a tbody
    newrows = [];
    for (var i=0; i<tbody.rows.length; i++) {
    newrows[newrows.length] = sorttable.copyTableRow(tbody.rows[i]);
    }

  202. Any release date for Version 3 ?

    I’m sure it’s been suggested, but sorting by multiple columns would be very useful.

    My company would pay $$$ for Version 3, since it is the least process intensive script for sorting we have come accross.

    Cheers once again for the great work

    Mick

  203. Mick: I’d be happy to talk about custom paid enhancements to sorttable; those custom enhancements can go into sorttable v3, certainly. Do please drop me a line (http://www.kryogenix.org/contact) to talk about the enhancements you’d like!

Post a comment.