Finished jQuery Tablesorter mod for Collapsible Table Rows

Posted by Dan on Mar 28, 2008 @ 10:31 AM

I've been pretty quite the past two weeks. I've been really plugging away doing a lot of client-side UI programming in jQuery. I'm working on a complete revamp of some portions of our application and than means modernizing the UI.

One of the tasks I needed to accomplish was to create a UI component that would allow for sortable, collapsible table rows. jQuery already has a very good (an official) plug-in for sorting column rows called tablesorter.js. The Tablesorter is part of the jQuery UI project and allows for sorting of multiple columns—which is a really nice feature.

However, the current tablesorter.js codebase does not have anything in place to allow for "children" rows—which is needed to provide a collapsible architecture. Essentially I need a way to tell certain rows that they belong with the row above.

After playing around with some different variations I finally came up with a solution that worked elegantly and had minimal impact on the Tablesorter codebase. The way I solved the problem is to add a class to "children" rows, which tells the Tablesorter plug-in to include the row as part of the last row that does not have the "child" class. This allows me to actually have multiple children rows, that are all grouped together and ignored by the sorting algorithms.

I'm working with Christian Bach to get the mods added to the official codebase—and it looks like that might happen as early as next week. I've upload my Tablesorter mod and an example of implementing collapsible rows.

The example uses the "Pager" add-on for Tablesorter, just to show my mod attempted not to break backwards compatibility.

If you have any comments, please leave them. They will only help me and Christian in the long run.

Categories: jQuery

149 Comments

  • Patrick Whittingham's Gravatar
    Patrick Whittingham
    Dan -

     How's the performance with lots of rows of data? Have you seen a 'limit', before slowness occurs?
  • @Patrick:

    The majority of overhead is actually in initializing the core table sorting code. My mod to support child rows does not seem to have a huge impact on performance (but I was testing only on a couple hundred rows of data.)

    DOM parsing is always going to be problematic when you get in to tens of thousands of elements. I'm not sure what you consider "lots", but if you're getting into 100's of lines of tabular data, you probably want to start thinking about implementing that data in a progressive manor. I mean even just having a browser try to render a table with hundreds or thousands of rows is time consuming--parsing that DOM tree is obviously only going to add more overhead.

    So, if you're talking about a reasonable dataset then performance is fine. If you're wanting to load thousands of rows of data, then you really don't want to preload all that data anyway (because that's a ton of data to push to the user.) You really want a solution that will load the data progressively (i.e. via AJAX.) That's going to be more efficient all the way around.
  • Looks good!
  • First of all:
    Thanks for sharing your code!

    One question:
    It seems that your tablesorter-script does not accept header-inline (meta) information.
    Meaning: <.... class="{sorter:false}" ....
    is not working.

    Using the header-Option in the ready-container is in my case not an option.

    You have have a solution for this, please let us know :-)

    Thanks again!
    Cheers, QT
  • QT:

    The metadata works fine, I'm using it on the project I originally wrote the mod for. Are you sure you've included the metadata plugin?
  • @Dan:
    Thanks for getting back so quick.

    Yes, a metadata-plugin was included (emphasis on *a*).
    I noticed that I was using one from Joern ( * Revision: $Id: metadata.js 3465 2007-09-23 21:15:52Z joern.zaefferer $) and not the one from the jquery-repository.

    Now it workes like a charm!

    Thanks again.
    Cheers, QT
  • Thanks Dan,
    two quick questions.

    1) how does one not use the +-... Say I want a link to expand my rows...

    2) the 'js file makes reference to FX - and I've tried to put show("slow") in the context of the call, but it bombs...

    .collapsible( "td.collapsible", { collapse:true },fx: {hide("slow"),show("slow")} )

    thanks again.
  • @James:

    If you notice, the FX don't work correctly in IE6 (which is why they're just "show" and "hide".) Also, the "fx" argument just takes a string (like "show" or "slideDown") you currently can't specify a speed. However, since IE6 doesn't like to animate table row elements (TR) I never really went forward with completely adding the FX.

    As far as using a link, the way the code will work is it'll attach the "expand/collapse" function to the first "link" it finds in the collapsible cell. If there is no link, it creates the a link for you. So, just add a link with whatever verbiage you want to the collapsible cell and the behavior will automatically be attached.
  • Hi Dan -

    Thanks a million for sharing your update and for closing the deal on completely converting someone over to jquery. I just starting using it (I used the tab UI) and was upgrading my db display to include dependant rows, include sortability and pagination - and what do you know? Found it here with your upgrade and jquery table sort! Koodos - works like a charm, is fast and lightweight!

    New fan!
  • Great mod of a great tool. Anyway I can filter the data? A widget perhaps?
    Thanks!
  • @kab:

    Yeah, you'd need to write a widget. I'm pretty sure I've seen a filtering widget someone wrote for the tablesorter plugin. I'd suggest checking out the jQuery mailing lists.
  • How would I add an "expand all/collapse all" link at the top of the table?
    Thanks
  • @kab:

    You can do this to toggle the current state for all rows:
    $("td.collapsible a").click();

    If you want to collapse all do:
    $("td.collapsible a").addClass("expanded").click();

    If you want to expand all rows do:
    $("td.collapsible a").removeClass("expanded").click();
  • Thanks. This is a great mod!
    For others interested this is what I have used:
    // Expand/Collapse all
    $('a#expandCollapse').click(function(){
    var linkLabel = this.innerHTML;
    switch(linkLabel)
    {
     case "Expand All":
      $("td.collapsible a").removeClass("expanded").click();
      this.innerHTML= "Collapse All"
      break;
    case "Collapse All":
      $("td.collapsible a").addClass("expanded").click();
      this.innerHTML= "Expand All"
      break;
    }
    return false;
    });
  • Dan - Excellent mod and thanks for sharing it!!

    Has anyone had any success adding filtering? I have not been able to find a widget to do so, but I do know that filtering was being worked on for the next release of table sorter. Here's the link to his demo: http://motherrussia.polyester.se/pub/jquery/demos/...
  • @Rick:

    I'm not sure where Christian's at as far as filtering goes. It's definitely a feature that's needed to complete with other table sorting modules.
  • Is this compatible with cflayout?
    If I use it on it's own works great, if I use it in a cflayout it gives an error (cflayout: Error processing JavaScript in markup for element cfdiv...) and the table sort is all broken.

    Thank you for your work,

    Mike
  • how would you make it so just one row can be expanded, so if you click on expand button from another one previous just closes?
  • @Mike:

    I've never used cflayout, so I can't say. I prefer implicitly controlling the behavior of my applications and there's just to much JS overhead in the current implementation of some of the CF DHTML tags (at the moment) for my liking.

    From the error, it sounds like it's a problem with cflayout processing the script tags inside your content. You might try adding a the defer="true" to your script tags that you're loading inside cflayout:

    <script type="text/javascript" defer="true">
    // code here
    </script>
  • @Carlos:

    You'd need to modify the $a.bind("click", function (){}) function to trigger the "click" handler for every anchor that's not the current anchor. You'd need something like:

    $("td.collapsible a").filter(function (){return this !== $a[0]}).addClass("expanded").click();

    This should find all the anchors, but the currently clicked item and toggle it's status to collapsed. (I did not actually test this code. If doesn't work exactly, it should be pretty close.)

    Note that this method could be really slow on large tables though.
  • Thank you Dan for the quick response.
    Unfortunately it didn't fix it :)
    I agree with you that ajax implementation in cf8 is on the bloated side.
    I guess I will be looking for other js libraries that can offer similar functionality with cflayout.

    Thanks again
    Mike
  • @Mike:

    My guess is if you load the JS libraries in the main container (and not within the template you call with <cflayout>) you can get things to work.

    I suspect there definitely is a way to get things working and you may run into similar problems with other libraries as well.
  • well, by moving the JS libraries in the main container the error went away but the table is still broken, no +/- to collapse (all the rows are displayed) and no sorting.

    It's a cflayout problem I know. Will dig a little bit more but at this point there is not a lot I can do.

    Thanks again and keep up the good work
    Mike
  • @Mike:

    You'll need to trigger code when the cflayout window is opened that will actually attach the behavior to the table. There should be some JS variables that are exposed which allow you to run JS code when the layout window gets opened.
  • Hi Dan,

    The plugin is excellent. Really well put together. Have you considered adding row highlighting to the mod or heard of anyone successfully adding it?

    Thanks,
    Ryan
  • @Ryan:

    Thanks! At this time, I don't require the functionality in the project I'm working on, so I have no plans to add it. You could definitely write something to do row highlighting. I know there are several jQuery plug-ins out there already that do row/column highlighting. You'd probably need to modify those plug-ins to support multiple rows being seen as a single row, but they'd give you a good head start.
  • Just thought I'd throw it out there before developing on my own. I've got a solution and it's working great with your plugin. Thanks again.
  • For the cflayout error, I've been trying to find a solution and came across this blog entry that might help:
    http://www.justanaverageyo.com/index.cfm/2008/1/17...
  • Answer for Filtering with TableSorter.
    When one uses the append function for Ajax one can pass a function "()" instead of a URL "string". This JS function would return a dynamic URL.
    Each time you will need to clear data set and perform a reset with the new ajax return string.

    $("#ajax-append").click(function() {     $.get("assets/ajax-content.html", function(html) {       // append the "ajax'd" data to the table body       $("table tbody").append(html);       // let the plugin know that we made a update       $("table").trigger("update");

    Mod
    $("#ajax-append").click(function() {     $.get(GetHTML(), function(html) {       // append the "ajax'd" data to the table body       $("table tbody").append(html);       // let the plugin know that we made a update       $("table").trigger("update");
  • @Kurt: would you be interested in adding this code to my current project? If yes, please contact me for details and give me an idea on costs. subs at i2tsolutions dot com Thanks!
  • I think there may be a bug. If I load rows in via ajax and then fire the script below, the sorting and collapsing no longer work. Maybe it's something I'm doing wrong?

               jQuery(".tablesorter:has(tbody tr)")
                 /*
                  * td.collapsible = collapse to the first table row and show +/-
                  * td.collapsible_alt = anchor to order number
                  */
                 .collapsible("td.collapsible", {
                     collapse: true
                 }).trigger("update");
  • nm. works great, I was doing something wrong. Thanks for the great plugin!
  • //@ Mike
    // How to make row highlighting and toggle one row expand/collapse
    // Make sure to give your first tr row a class='first_row_class'

    // row hilite
    $("tr.first_row_class").hover(
    function () {
     $(this).children('td').attr("style","background-color:#e6edc1"); // row hilite colour
    },
    function () {
     $(this).children('td').removeAttr("style");
    }
    );

    // row toggle click
    $("tr. first_row_class").click(function(){
        $(this).find('td.collapsible a').click();
        //return false;
    });

    // PS. Great plug-in!
  • I have the same call going to different tables in an html page. Is there a way to shorten/combine elements like this so each one toggles independently yet doesn't take 6 lines?


    $('#table-products1').columnManager({listTargetID:'targetcol1', hideInList: [1,2,3,4], colsHidden: [5]}); var opt = {hide: function(c){ $(c).fadeOut(200); }, show: function(c){ $(c).fadeIn(500); }};
    $('#table-products2').columnManager({listTargetID:'targetcol1', hideInList: [1,2,3,4], colsHidden: [5]}); var opt = {hide: function(c){ $(c).fadeOut(200); }, show: function(c){ $(c).fadeIn(500); }};
    $('#table-products3').columnManager({listTargetID:'targetcol1', hideInList: [1,2,3,4], colsHidden: [5]}); var opt = {hide: function(c){ $(c).fadeOut(200); }, show: function(c){ $(c).fadeIn(500); }};
    $('#table-products4').columnManager({listTargetID:'targetcol1', hideInList: [1,2,3,4], colsHidden: [5]}); var opt = {hide: function(c){ $(c).fadeOut(200); }, show: function(c){ $(c).fadeIn(500); }};
    $('#table-products5').columnManager({listTargetID:'targetcol1', hideInList: [1,2,3,4], colsHidden: [5]}); var opt = {hide: function(c){ $(c).fadeOut(200); }, show: function(c){ $(c).fadeIn(500); }};
    $('#table-products6').columnManager({listTargetID:'targetcol1', hideInList: [1,2,3,4], colsHidden: [5]}); var opt = {hide: function(c){ $(c).fadeOut(200); }, show: function(c){ $(c).fadeIn(500); }};
  • @Itsy:

    You can combine selectors by using a comma to separator each unique selector:

    $('#table-products1,#table-products2,#table-products3,#table-products4,#table-products5,#table-products6').columnManager({listTargetID:'targetcol1', hideInList: [1,2,3,4], colsHidden: [5]}); var opt = {hide: function(c){ $(c).fadeOut(200); }, show: function(c){ $(c).fadeIn(500); }};
  • Tablesorter is relly good.

    However, as a CF programmer I am quite new to Jquery. I got Tablesorter to work with CF pulling data from mySQL but I can't seem to get the Expand/Collapse ( Kab ) and the Row Highlight ( David ) to work. It's the HTML call to the functions I suspect. I would really appeciate any help in getting these working.

    Nice one Dan. Great peice of coding.
  • Hi Dan,

    I started to play with your mod to the tablesorter. It is really great.

    Does your mod work with having a child sortable table? I had a problem with it trying to sort the parent table.

    In the end I am hoping to have additional child tables that can have child tables themselves with the ability to be sortable, etc.

    Example of what I'm trying to accomplish is similar to this:
    http://demos.telerik.com/aspnet-ajax/Grid/Examples...
  • @Michael:

    I think you may need change the tablesorter code further to make sure that only tr that are direct descendants of the table/tbody take are sorted (ie. "> tr".) I'm not sure how well the tablesorter code works with nested tables, because I've never tried it.
  • Dan,

    Thank you for the quick reply. I quickly looked into your jquery.tablesorter.mod.js and found the following code:

    function buildHeaders(table) {
      ...
         $tableHeaders = $("thead th",table);
      ...
    }

    I changed the selection to:
    $tableHeaders = $("thead:first th",table);

    Now my nested sortable tables sort only the rows within their own table.

    With that I plan to play with this more, but so far this is great!!!

    I noticed I had download jquery.tablesorter.collapsible.js and jquery.tablesorter.mod.js

    You stated in this blog that you were working with the author to integrate your changes. Is that still in the works? This is great none the less.
  • @Michael:

    I believe Christian implemented most of my changes in his source code, but I don't think he's ever released a new version of the code.
  • @Dan,

    I looked at this a little more this weekend. I found Christian's svn version:2.0.5b. Which incorporated your efforts into his code. Just for others you still need to use Dan's jquery.tablesorter.collapsible.js. This time I didn't need to make any changes to the buildHeader function like I stated in a previous post. When clicking the header to sort it correctly only affected its current table.

    I did have issues with providing the table with initial sort order information or using the tablesorter.trigger("sorton", [[[0,1],[1,1]]]);

    It binds the event: .bind("sorton",function(e,list)

    By default it propagates to matching parent elements, which was bubbling up to all the parent tables to re-do the initial sort order. I just added e.stopPropagation(); for the first line in the function to tell it not to bubble up. That fixed that.

    I also made a selector change on his code for using the zebra widget:
    $("#" + table.id + " tbody>tr:visible:not('.expand-child')").each(function(i) { ...

    This fixed it from trying to apply zebra to any child tr rows. Depending on usage you might want, but my child table's themselves were having tablesorter applied.

    It all appears to be working perfectly for me so I thought I would share if anyone else wants to venture into having detail tables as the child row.
  • Hi all

    I have a small query. I need a table, i have a column in that table containing a link. On clicking on that link the rows should expand between that row and the next row.

    can anyone help?
  • @Hi All:

    This mod should handle that for you, but you'll need to refer to the source code to see how to do it.
  • Hi,
    I am still working on my table (since november). The goal is to present a table and display the last column only if the user is privileged to see it. If the user is credentialed then a input button will display which allows the user to toggles on and off the last column.
    I have something which works on IE but not on FF.
    Has anyone successfully done this? Dan - would you be able to look at the code if i send it? Desperate...
    Thanks...
  • @Itsy:

    I don't have time to look at it, but in FF it should be as simple as hiding the last TD:

    $("#table > tr > td:last").hide();
  • hi dan, great mod, perfectly suited my needs :-)

    however, after putting it to use in a number of places, i have encountered a problem that i can't resolve. basically i have a table with a number of tabs above it (manifested by a <ul>). these tabs when clicked repopulate the table by pulling some data via AJAX. however, once a tab has been clicked the functionality of table sorter is lost - even if i go back to the "original" tab, i.e. the one that is selected on page load. the only way to get the functionality back is to refresh the page in the browser.

    any idea what might be causing this, and any possible solutions? i've been recommended livequery but i couldn't get that to solve the problem. THANKS!
  • @Nick:

    You need to rebind the events. See this page for an example of rebinding the tablesorter:

    http://tablesorter.com/docs/example-ajax.html
  • @nick

    Dan's mod should resemble the same functionality that you can achieve with the original tablesorter.

    Look at: http://tablesorter.com/docs/example-ajax.html

    You probably need to do the following:
          $("table").trigger("update");
  • thanks for the help guys, this didn't work though :-(
  • @nick than it sounds like you are overwriting the entire table which is unbinding the tablesorter events.

    You need to look at how you are modifying your table on each tab click or you will have to re-initialize the tablesorter by calling the table.tablesorter(configSettings) on every tab click.
  • thanks for this guys, seems it worked :-), a little unpredictably at first, but after some modification of the surrounding code, it's now working perfectly.

    THANKS SO MUCH! not only for your help but a great modification to the tablesorter :-)
  • Is there a way to expand a particular row by default e.g. 1st and the 3rd?
  • @Rish:

    Assuming you're using a <tbody /> to store your data, this would expand the first row:

    $("tbody tr:first td.collapsible a").click();

    All you need to do is trigger the click handler for the <a /> element inside the td.collapsible cell inside the appropriate row.
  • Hi Dan,
    I like your works a lot. I've used the collapsible and very happy with it.
    I current have a issue with collapsed row on nested tables. It works fine with a first rows, but when I nested tables within rows, when I click on the (+) of a first row all rows inside expanded, I have to double click on the (+) to get it collapse back.

    === jquery===
    <script type="text/javascript">
      $(document).ready(
        function (){
          $(".tablesorter")
            //td.collapsible = collapse to the first table row and show +/- td.collapsible_alt = anchor to order number
            .collapsible("td.collapsible", { collapse: true })
            // do sorting
            .tablesorter({
              // set default sort column
              sortList: [[2,0]], headers: {0: {sorter: false}} //, widgets: ['zebra']
                , onRenderHeader: function (){ this.wrapInner("<span></span>");}
                , debug: false
              })

        }
      );
    </script>

    === html part ===
    <table class=tablesorter><thead><tr><th>name</th><th>address</th></tr></thead><tbody>
     <tr><td rowspan=2 class=collapsible></td><td>name_1</td><td>address_1</td><tr>
     <tr class='expand-child'><td colspan=5>
      <table ><thead><tr><th>class</th><th>description</th><th>teacher</th><tr></thead><tbody>
       <tr><td rowspan=2 class=collapsible></td><td>class_1</td><td>description_1</td><td>teacher_1</td><tr>
       <tr><td rowspan=2 class=collapsible></td><td>class_2</td><td>description_2</td><td>teacher_2</td><tr>
       </tbody></table>
    <//tbody></table>

    The problem is when I click on the (+) next to name_1, I see both class_1 and class_2 rows and the (+) sign. when I double click on (+), it is collapsed. Do you have any idea?

    Thanks,
  • @Linh:

    I've never needed nested table support, so I don't know how far this will get you, but you will definitely need more specific selectors.

    When you use the selector "td.collapsible", it's going to look inside the table for all matches--which will include the deeply nested matches of your inner tables.

    Instead you'll need to use something that has more specificity like:

    "> tbody > tr > td.collapsible"

    This would make sure to only get the direct descendants you're after (i.e. the outer most "td.collapsible" elements in your table.

    You may also need to modify the collapsible code to be use the direct descendant selector (ie. ">") so that it's not grabbing all td elements when trying to reveal the collapsed data.
  • Hi Dan,

    Thank you very much for your comments. Here is what I have changed on

    <script type="text/javascript">
      $(document).ready(
        function (){
          $(".tablesorter")
            //td.collapsible = collapse to the first table row and show +/- td.collapsible_alt = anchor to order number
            .collapsible(">tbody >tr >td.collapsible", { collapse: true })
            .collapsible(">tbody >tr >td >tbody >tr >td.collapsible", { collapse: true })
            // do sorting
            .tablesorter({
              // set default sort column
              sortList: [[2,0]], headers: {0: {sorter: false}} //, widgets: ['zebra']
                , onRenderHeader: function (){ this.wrapInner("<span></span>");}
                , debug: false
              })
            // do paging
            .tablesorterPager({container: $("#pager"), positionFixed: false}) ;
        }
      );
    </script>

    .collapsible(">tbody >tr >td.collapsible", { collapse: true }) ==> is for outer most table
    .collapsible(">tbody >tr >td >tbody >tr >td.collapsible", { collapse: true }) ==>inner table

    The outer rows are working OK, the inner row are not collapsed.
  • @Linh:

    As I said, you'll probably need to modify the source code of the collapsible plug-in as well. Look for the selectors used and make sure they're be very specific about the <tr> and <td> elements their selecting.
  • @Linh:
    I know I've made comments in here of some things I did and I did have to alter the source code in certain places. I actually used Christian's tablesorter svn version:2.0.5b that incorporated a lot of Dan's work. You still requires jquery.tablesorter.collapsible.js as well.

    Here is a snap shot showing collapsible tables that are sortable and themselves can nest other collapsible tables. http://picasaweb.google.com/lh/photo/S58apsVqEFfKQ... Look at my previous posts in here to see if it helps, but if I have time and when I get to my workstation I'll see if I can post some code for you.
  • Hi Michael,

    The snap shot look great, it is what I would like to do. How did you change code on the 'jquery.tablesorter.collapsible.js'. Thanks for the comments.
  • Hi Dan,

    I've tried to change something in the 'jquery.tablesorter.collapsible.js' file. It is not get better, it is not working at all. because I am new with jquery, maybe.

    <table ...>
    <tr><td class=collapsible></td> ... </tr>
    <tr class='expand-child'><td>
         <table ...>
         <tr><td class=collapsible></td> ... </tr>
         <tr class='expand-child'><td>
             <table ...>
             <tr><td class=collapsible></td> ... </tr>
             <tr class='expand-child'><td>
                 .....
             </td></tr>
             </table>
         </td></tr>
         </table>
     </td></tr>
    </table>

    if I have several nested rows/tables like this. How would I change on the plug-in source code? would you please give me a hint? Thanks.

    Linh
  • I love the tablesorter and collapsible, thanks for sharing your works. How to add collapsed / expanded all rows of a table?

    Thanks,
    Ajay
  • @Ajay:

    There are a couple of examples in the comments, like this one:
    http://blog.pengoworks.com/index.cfm/2008/3/28/Fin...
  • Hi Dan,

    Thanks for a quick reply. It works like a champ. However, it expand and collapse all rows in tables. I have two tables, the inner table inside <tr><td> of a outer one. how to collapse/expand all rows of a inner table while keep outer table stay still. is there an additional modification on the source code?
    Again, thanks very much for sharing your work.

    Ajay
  • @Ajay:

    Just make your selectors more specific like:
    $("#tableId > tbody > tr > td.collapsible a").removeClass("expanded").click();

    Which would only collapse at the first level of table cells. You're going to need to adapt the selector for you environment, but the basic idea is to make sure that you only grab the specific cells you want to expand/collapse.
  • Hi Dan,

    Thanks so much. It works on the outer table cells (only one table). However, I like collaped/expanded all in the inner tables cells only. so I do like I've done on the outer table. It works only on the 'first/top' inner table cells. This is strange. Do you have any clue?
  • @Ajay:

    Without seeing an example, it's impossible for me to give you any clues, other than it's probably just a matter of getting your selectors right.
  • Hi Dan,

    Thanks for your comments. All selectors look right, it just display incorrectly. I have the HTML and javascript @ http://sites.google.com/site/ajaynguyen/ . I don't have a public DNS, so you cannot see a real display. but I will post the snapshot later. Thanks for the help.

    Ajay
  • @Ajay:

    Your HTML is malformed--so that can definitely affect things. The "id" attribute must be unique and all your inner tables have identical values for the "ids." jQuery will only ever grab the first one.

    Also, your inner tables are missing the <tbody> tags.

    There are other errors in the HTML as well. I'd recommend running your code through an HTML validator. Once you fix your HTML, you may find it resolves the issues you're having.
  • Hi Dan,

    Thank you very much for your help. I validated the HTML, change table ids to unique ids, but it is not working properly. I post the html/js code and snapshots @ http://sites.google.com/site/ajaynguyen/ . All data are generate dynamically from DB. I think I almost get a result. your help would be very appreciated.

    Thanks again.
    Ajay
  • David MÃ¥rtensson's Gravatar
    David MÃ¥rtensson
    Hi,

    I got a problem getting tablesorter to work in my page.

    I use jQuery 1.3.2 and try to add sort to two tables that are contained within a main table.

    The selector for jQuery works and the debug info also seems correct but I do not get any result.

    Built headers:,2ms
    []
    column:0 parser:text column:1 parser:text column:2 parser:digit
    Building cache for 3 rows:,0ms
    Built headers:,0ms
    []
    column:0 parser:text column:1 parser:text column:2 parser:digit
    Building cache for 3 rows:,1ms

    Pageurl: http://lab.dnet.nu/bugs/?view=todo.todo

    All css and js files looks to be loading fine and I get no js errors.

    Can any one see any obvious errors?
  • David MÃ¥rtensson's Gravatar
    David MÃ¥rtensson
    Got it working now, only the images what do not display, but I think I can fix that.
  • Great mod to tablesorter plugin - just what I was looking for. Is there any way to put the header for the child rows? I don't really need a header for my parent row, as I'm only displaying two items. The majority of my data will be in the child rows, and I'd like to put a header there//
  • @KathyS:

    I'm not sure if I understand what you're saying, but if the children that you really want sorted (and is really where the tabular data is) then I'd only apply the tablesorter to the children.
  • What I've got it a bunch of parent records - company info, and multiple child records for each parent (not the one-to-one like the example). I want to be able to sort by both the parent and the child records if possible...
  • @KathyS:

    If you start reading at Michael comment (link below) you'll see conversations about doing what you want. I've still never tried it, but Michael got it working for himself:

    http://blog.pengoworks.com/index.cfm/2008/3/28/Fin...

    There's also other dialog in there about getting child sortable tables working.
  • Now I'm trying to page everything, and the pager does not seem to display all the data. I know the query is correct because I echo all data to error_log. I have multiple child rows for each parent row. If I don't use the pager.tablesorter plugin, all the data is correct and displayed ok. If I use the pager plugin (which I really need cuz there is lots of data), several child rows are not displayed for each company record, and one company record is not displayed. Anyone seen this before?
  • Thanks for the great mod!

    I am quite new to JS, and I have managed to get your mod working but I ran into a problem when appending data using the AJAX example on the tablesorter website. The tablesorter function still works after appending the data, however the new TD's with the "collapsible" class are not getting set as collapsible (no +/- button appended to the TD.

    I am calling $(.tablesorter).trigger("update");, is there something else I need to do as well?
  • @Matt:

    The tablesorter mod was not intended to work w/tables populated via AJAX. It only allows the behavior to be bound to a table once, so once you append data to the table via AJAX, there's not a good way to re-bind the behavior.

    To accomplish what you want, you'd have to customize my mod further to allow re-binding of new data.
  • This works great on your site. Any idea why I am getting the following JS error message?

    h[list[i][0]]
    jquery.tablesorter.mod.js (line 411)


    Also, I am not getting the +/- images like in your example. I don't think the JS is adding anchors to my <td class="collapsible"></td>.

    TIA
  • opps...

    h[list[i][0]] is not defined
    jquery.tablesorter.mod.js (line 411)
  • Heya,

    This Mod is great, use it a lot, one question I had is, "Is it possible to have nested rows to be expandable? For example if I wanted a layout as:

    [+] Row
       [+] Row

    How would I accomplish this? I seem to be able to only do one expandable row for each TR and thats it, is it possible to have more than one without nesting another table in a <TD> ?
  • Meant in the above example:

    [+] Row
    .....[+] Row
  • Hi,

    It's great plug-in... thanks. Have one question: How to track the click event of the current [+] as expand (or) collapse?

    Thanks,
    Ranga
  • @Ranga:

    State is all stored in the className of the +/- anchors. You can determine the state by examining which class is assigned the anchor.
  • A wonderful script! But I get a javascript error in IE 8. The error is in jquery.tablesorter.mod.js on line 491, it's the return statement. "'undefined' is null or not an object"
    function getCachedSortType(parsers,i) {
       return parsers[i].type;
    };

    Do you know what it is? It works perfect in IE 7 and in Firefox.
  • @Charlotte:

    The version up on my server was pretty outdated, so try re-download the script and try the newer version.
  • Very nice Dan!

    This will help out my application a lot: http://theeasyapi.com I was looking for something that did just what you put in there. The only difference is that I spent 2 days trying to go at it on my own and using QuickSand instead of TableSorter. Should have dugg harder and found your post. Also check out The Easy API (the link is above) I think you could use it. We provide an API that interfaces other API's and makes things easier to access data.

    Nice job, and thanks for making me stop banging my head off the wall!
    Chad
  • very nice example : http://www.pengoworks.com/workshop/jquery/tablesor... but when I need to add Quicksearch to the table there are a lot of problem in showing rows.
    Please can you check this for me by adding a search input and the exemple still work fine.
    thanks Dan !
  • Hi, how can I sort values like this: 1.000,00 or 1.000.000,00 (brazil currency)
    I tried to change the regex without success

    Thanks
  • @Rafael:

    I'd check with the tablesorter plug-in site to see if there's isn't already something available: http://tablesorter.com/

    If there's not, you're going to need to write something that will convert the European numbering format to something JS can interpret as a number (which is the standard US formatting.)
  • Hi Dan,

    First, love the mod! Really really nicely implemented ;)

    Second - i'm trying to use it to sort a grouped table, sorting both groups and within groups.. But i'm having real issues working out how to do this. Do you know if anyone else has approached this problem?

    You can see some source code and a better description here:
    http://stackoverflow.com/questions/2537534/jquery-...
  • Has anyone done any modifications to allow dynamic data?
  • Hey Dan,

    Very good idea - and I would really like to implement it into my projects. However when I replace this code, with my current table sorter code, it no longer works. No errors are thrown or anything - it just doesn't work. Does this work with the latest versions of jQuery? And if not, how could that be remedied?

    Thanks!
  • @Nick:

    I'd assume it works with the latest version of jQuery. I know it works under 1.3.2--which is the last version I actually tested with. I'd recommending trying both tablesorter libraries in my example w/the latest jQuery and see if it works. If it does, then the problem is with the tablesorter.

    Remember, I had to mod the tablesorter to get things to work.
  • Hi Dan
    Really nice mod you've made. There is one issue I haven't been able to fix, it's the separator, thousand separator acctually, and decimals. How do I attach a surtain separator to the field?

    I've tried to use this.

    <th class=\"{sorter: 'digit'}\">

    And

    <script type="text/javascript">
                $(document).ready(
                    function (){
                        $(".tablesorter")
                            /*
                             * td.collapsible = collapse to the first table row and show +/-
                             * td.collapsible_alt = anchor to order number
                             */
                            .collapsible("td.collapsible", {
                                collapse: true
                            })
                            .tablesorter({

                                headers: {
                        3: {
                          sorter:'digit'
                        }
                      }
                        })
                            ;

                    }
                );

        </script>

    But with no sucess
  • @Philip:

    I'd recommend contacting the creator of Tablesorter for support.
  • Dan, Thank you for this. It saved me (probably) hours of tearing my hair out! Worked like a charm.
  • Hi, Dan,
    It very nice mod,Thanks!
    but,it seems cannot work well at inner table; when I click on a inner table to sort it, it will go wrong:

    parsers[i] is undefined
    [Break on this error] return parsers[i].type;
    --at line 492

    How can I fix it?
  • Dan:
    Thank you for implementing this. It made my implementation of tablesorting so much easier. One request - the documentation on this and original tablesorter is a bit sparce. if you could add some more examples, it would make using the interface much easier for others. If you want, I can forward you my examples to be posted in the documentation.
    Thank you,

    Marc
  • Hi Dan, this is a fantastic mod.

    One question, though: I need to be able to display the "parent" rows below the child rows rather than above. Is there a way to do this? I tried making some modifications myself, but didn't get anywhere.

    Thanks,
    MR
  • @M.R.:

    You'll have to do a good bit of refactoring to get that type of functionality. I'd really recommend looking for another plug-in that has that functionality built-in, but honestly I don't think I've ever seen an example of that type of UX in an application and it doesn't seem like it would be very intuitive.
  • Thanks for the quick response. My client wants to show a data table with the sales figures for a particular company in the parent row, and sales for specific products of that company in the child rows. So because the parent rows would actually function as "totals" of the child rows, it makes sense to have them on the bottom. Then, the table would be sorted first by the parent's sales column, and then be sorted by child within each group.
  • Dan,

    Thnx for the great plugin. Everything seems to work fine, but what I want is that only one row can be expanded at the same time. All other rows need to be collapsed if you expand a new row.

    I found this piece of code in one of your comments that should do the trick.
    $("td.collapsible a").filter(function (){return this !== $a[0]}).addClass("expanded").click();

    I've added that at the end of function $a.bind("click", function (), but that didn't seem to work.

    Do you have any suggestions how to get this right?
    Thnx in advance.

    Paul
  • @Paul:

    Looking at the code again, you're going to need to add a check to the code so that line only runs on the initial click--you don't want it running for the elements where the event's being triggered programmatically--otherwise it'll collapse all rows.
  • I have a problem with alternating row colors when i have nested tables inside tablesorter table. It starts OK with even/odd classes in alternating rows but as soon as it reaches the first cell with nested table all the rows below continue as odd. However, when i click a header to sort, the problem disappears.
  • @S:

    There's several comments above about nested tables that may help you, so I recommend reading through those to see if any of that information helps you.
  • I'm interested in having a column that contains the ID's of users.
    I'd like whenever one of these users ID's are clicked on to basically be a link to collapse or expand their line in the table.
    Basically I want to emulate the purpose of the + button on the left.

    Could someone point out how this would be done?

    Thanks,
    Justin
  • @Justin:

    All you should need to do is add the "collapsible" to the parent TD element containing your ID and then wrap your ID in an anchor tag. For example:

    <td rowspan="2" class="collapsible"><a href="#">1234</a></td>

    The collapse/expand functionality should attach itself to the anchor tag.
  • Dan,

    Thanks for your input but I'm still having one problem with this.
    It does bind it to the anchor tag, but the problem is once the anchor tag is clicked it actually forces the + or - box to appear underneath the text.

    This is also causing erratic behavior in the way sub-cells are colored.

    See here: http://assets.strose.edu/firstalert/admin-view.asp...

    Any thoughts?

    Thanks,
    Justin
  • @Justin:

    You need to get rid of the ".collapsible a.collapsed" and ".collapsible a.expanded" CSS statements--or at least alter them to however you want the links to look.

    The problem is strictly CSS related.
  • Hi Dan,

    Thank you so much for your work it is exactly what I'm looking for!

    Although most of your code integrated with my project, I had a couple questions I was hoping you could resolve for me:

    1) How would I go about making the entire parent row clickable instead of just the + sign?

    2) When my site loads, it first loads all of the parent with children rows expanded, then quickly collapses to hide them. This happens every time the page is refreshed. I tried creating a div inside the <td> with <div style="display:none;"> but that prevents the row from expanding entirely.

    Hope you can help me and thanks again for your contribution!
  • @Steven:

    1) You can attach a behavior to the row that would call something like this on the current row:

    $(currentRow).find("td.collapsible a").click();

    This should toggle the current state.

    2) If you look at the source code of the example, you'll see the following:

    /* use the below style below to hide the collapsed rows via CSS, you must also set the showCollapsed setting to true */
    /*
            table.grid tr.expand-child td {
                display: none;
            }
    */

    You can apply that style to hide collapsed rows by default, but make sure to set the showCollapsed to true.
  • Thanks Dan for the response!

    I got the second part of what you said to work, but I'm still having trouble understanding what you proposed for the first question.

    Am I supposed to bind the row to something then call your function in jQuery?
  • @Steven:

    Yeah, you'd need to do something like:

    $("table").delegate("tr", "click", function(e){
        $(this).find("td.collapsible a").click();
    });

    I didn't test it, but that should toggle the collapse state if you click anywhere within the row. The only issue is you might not to skip triggering the click() event the user actually clicked on the "+" arrow, since that will double trigger the event.
  • Thanks a lot for this, this has really helped me out today!!!
  • Hello,

    I have been trying to do, what Linh already posted - to have nested tables - tables inside td's of tr's classed with expand-child.

    Did anyone manage to modify the tablesorter.collapsible.js, so that the inner tables don't get expanded, when the outer gets?
    Check out this post: http://blog.pengoworks.com/index.cfm/2008/3/28/Fin...
  • Thank you in advance for an answer!
  • I solved my issue.
    In case anyone had the same problem like me or Linh:

    in collapsible.js I found this code:

    // show all the table cells
    $("td", $trc)[bIsCollapsed ? settings.fx.hide : settings.fx.show]();
    // get the next row
    $trc = $trc.next();

    and modified it as follows:
    if (bIsCollapsed)
    {
        $trc.find(">td").hide().end();
        $trc = $trc.next();
    }
    else
    {
        $trc.find(">td").show().end();
        $("tr.projectRow").find("td").show().end();
        $trc = $trc.next();
    }
    with my html code:


    <tr class="expand-child">
    <td class="dashed-border" colspan="4" style="padding:0;">


    //BEGIN OF INNER TABLE
    <table class="tablesorter_ppi">
        <thead>
    //UNIMPORTANT
        </thead>
        <tbody style="width:100%;">
            <tr class="showImm">
    //just assign any class to tr's you want to be expanded with a click of a (+) of the outer table - the content of tr's with a class expand-child, that are successors of tr.showImm will not be expanded alongside
  • projectRow should be showImm, misscopy-pasted
  • great job!
    thank you very much - this's exactly what i need and even more.
  • Has anyone noticed that with jQuery v1.4.2+ the default widgets aren't applied on instantiation? For example, the zebra widget isn't applied until you sort one of the columns.

    I'm not nearly as good at JS as I would like to be, but I've started poking around the code. If anyone has any suggestions, I'd definitely appreciate them!
  • I love what you have done making the sort work with children/expandable rows. I need to add quick search but when I do it misses up the sorting and displaying the parent children tables. Is there a fix for this? any help will be greatly appreciated

    Jerry Pierce
  • @Jerry:

    You're going to have to go through the code and figure out the issue. I haven't looked at the Table Sorter code in a very long time.

    I'm assuming whatever plug-in you're using to search doesn't have awareness of child rows, so you're going to have to modify it to work w/the mod.
  • How to increase default rowcount from 10 to say 50 or 100 for pagesize
  • @Haran:

    I didn't right the pager plug-in. I believe the author of the tablesorter plugin did. It looks like there's a "size" option you can pass in to change how many rows are on each page. If that doesn't work, you'd need to track down the author of the plug-in.
  • Hey Dan thanks a ton for your wonderful mod functionality. I did find the answer for my question. Thought of sharing this for others..  http://stackoverflow.com/questions/3051869/tableso...
  • @Dan- I see your tablesorter mod has an issue when there are no tr rows in the tbody.
    I am building a dynamic html where the number of rows can be anywhere between 0 and 15000. I see that when I don't have any rows beside my thead. your tablesorter mod throws an error. This indirectly has to do with your default sorting option to the 5th column.

    As a workaround I just populate a dummy\empty tr row with no values if my query returns back nothing. Also I remove the default sorting etc... This removes the script error on your mod file.
  • Hey Dan;
    Tried to incorporate dragtable with your code. When I drag and drop the columns only the visible parent rows drag and drop. Not the child rows. Any suggestions on that
  • @Haran M:

    I'd recommend just modifying the tablesorter mod so that the code that's causing the error doesn't run if the there are no rows.

    As for drag-n-drop, you'd have to write your code to move the hidden child rows along with the parent row.

    Since tablesorter seems dead, I'd look for a plug-in that has more of the features you need, rather than trying to hack together a solution that may not be terrible efficient to start with.
  • @Dan- Is your mod applicable only for static html table or can we have dynamic entries as well. Your paging seems to lock onto the initial load data only.
  • @Haran:

    You may have to destroy and re-apply the plug-in. I honestly can't recall. I'd seriously look for another plug-in that matches your needs better. I don't think Tablesorter has had any active development in the past 4 years.
  • "As far as using a link, the way the code will work is it'll attach the "expand/collapse" function to the first "link" it finds in the collapsible cell. If there is no link, it creates the a link for you."

    For some reason the link isn't being created for me, the page imports jquery.tablesorter.min.js and the table structure has the right class names I believe, but when I do a view source I see:

    <tr>
      <td class="collapsible"></td>
      <td class="collapsible_alt align-left">
        <!-- Account name -->
    </tr>
    <tr class="expand-child">
      <td></td>
      <td class="brand-data brand-name">
    ...

    Why does no link appear in that first TD? Also sometimes there will be 1 "expand-child" row and sometimes there will be 20, does the script care how many rows there are? As it varies I can't really use a fixed rowspan
  • Well I'm closer, had some imports wrong so the link shows up now at least!

    Related to an earlier question by someone here of not using the + sign, is it possible to expand/collapse rows by clicking anywhere on the parent row?
  • Would someone mind helping me with the Expand/Collapse all code in the comments above? Where do I add the code in at and how do i create the link to click on? Do i need to add CSS?

    Kab above posted this code.. and I am not having much luck figuring it out. I have everything else working very nicely tho!

    // Expand/Collapse all
    $('a#expandCollapse').click(function(){
    var linkLabel = this.innerHTML;
    switch(linkLabel)
    {
    case "Expand All":
     $("td.collapsible a").removeClass("expanded").click();
     this.innerHTML= "Collapse All"
     break;
    case "Collapse All":
     $("td.collapsible a").addClass("expanded").click();
     this.innerHTML= "Expand All"
     break;
    }
    return false;
    });

    Thank You,
    Todd
  • Is there a way to assign a custom key to sort dates, for example I have a date written "??-???-2005" Is there a way to assign a custom key to this value to get it to sort correctly

    Example, in the form of YYYYMMDD the above custom key would be 20050000

    Thanks in advance
  • Is there a way to have multiple tables and pagers on the same page? I'd like to have several. Playing around with the code and I can't get multiple of them to work.
  • @Luke:

    It should work fine, I've done it in the past. If you put up an example on JSFiddle (or JSBin, etc.) I'll certainly take a look at it and see if I can help you fix your problem.
  • Hi Dan, it is a great work from you. However it is a bit too complicated for my log head (new to jQuery and even java script). I 'borrowed' your demo code from your collipsible example and expanded into a nested table (http://jsfiddle.net/PhnZZ/1/). Then I found it is a total mess that the expand and table sorter function works across the nested table, not just the table it should be. Could you do a magical touch to fix this? If you can explain a bit more in detail, that will be much appreicated. Best regards! Many thanks, Jun
  • Hi Dan, it was great to see your work. However, I seem to be having issues related to the sorting of numeric columns once I use your plugin. For some reason I was just not able to get the sorting to behave properly. In fact I tried going back to the tests that come with the original tablesorter and changed the demo.html and included your js instead of the tablesorter.js and even the demo.html started getting sorted strangely. I don't know what I am doing wrong. Have you heard of this problem before?
  • Hi Dan, kindly ignore the previous post. I just found out that there was a part of the code I had written that was causing the issue with the sorting(specifically a parser). This is a great plugin and keep up the good work.
  • Hi Dan - I am looking at your example (http://www.pengoworks.com/workshop/jquery/tablesor...) and wanted to know if the following behavior was intended. If you expand a couple of rows and re-sort, the rows collapse. However, if you sort by Date (descending) the expanded rows are expanded.
    Are you explicitly requesting this behavior and if so where/how?
    I would like my expanded rows to collapse upon re-sort - do you have any suggestions? Thanks!
  • @KS:

    The rows don't collapse, it's just they've been sorted in a way you're not seeing them. You can verify this by:

    1. Load the page.
    2. Expand the first 2 rows.
    3. Sort by date desc (i.e. click the Date column again)
    4. Go to the last page of date
    5. The last 2 rows are expanded.

    If you want to explicitly collapse rows on sort, read through previous comments on how you can accomplish that.

    However, the tablesorter plug-in is really out of date and I really wouldn't suggest anyone use it for new projects. Find something more modern and robust that does what you want out-of-the-box.
  • Dan,

    I realize, the last post is a few months old. I have looked at a lot of other table sorters and this is still the best one, in my opinion. The only issue with this one that I could find, is the expand / collapse all with a sort that you and KS discussed. It is really not all but what is included on that page, which is actually better if you have a lot of records.

    I'm in the process of modifying it to use the sortEnd to expand or collapse the page after a sort, which will match the user's last choice. Also, I have plans to try and bind the same routine when changing pages that would fix the issue that you guys have described. This is where the actually working set, shown in the pager is better than working with all the records at once.

    I have looked at a lot of plugins and to mention one which has some good merits, Mottie has a good one, however, I would need to make major changes for my needs where yours is the closest to my needs. For now, I need the pager more than the filtering but I may try my hand at that as well later. Currently his has issues with filtering and using the pager at the same time. He has changed the link to open the expanded rows. For me, the link you had included will open a new page for that particular item. Later, I may look at adding a dropdown menu of predefined keywords for the filtering, including to be able to type them in as well. I guess you can say this is going to be a Table of Contents, which you can view the titles and optionally the expanded descriptions. The HTML markup on the child row's is definitely a plus.

    Thanks for a great plugin and it may not have all the bells and whistles as some of the newer ones but it is the closest out-of-the-box plugin that I have found to date.

    Thanks,
    RD
  • Have I understood this correctly?

    Your Tablesorter Mod is based on the original tablesorter. Mottie's version is also an improvement on the original version, but doesn't have the ability to hide/show child rows, like your mod does. And your mod doesn't work with Mottie's version at all?

    I'm a newbie and started using Mottie's tablesorter. But then I wanted hide/show capability for child rows and found your mod. I tried using it, but realized that it doesn't work with Mottie's version and it doesn't work with newer jQuery versions. Too bad :(
  • @Nikolas:

    I have not idea what "Mottie's version" is. It doesn't surprise me that it no longer works with any newer versions. My guess is it wouldn't take someone long to make it work. There's probably been restructuring of internal code. Keep in mind this mod is like 6 years old. :)

    I don't have any plans to update the code though.
  • Thanks for the fast reply!

    I'm referring to this as "Mottie's version":
    https://github.com/Mottie/tablesorter
  • Hi Dan,

    Currently, I am facing some issues with the jquery.tablesorter.mod.js file with the IE 11 browser. Actually, the problem is the tablesorter works fine in all the browser FF, Chrome, IE(8,9,10) but with IE 11 its not compatible. When the page loads it shows all the table data at once and when the page gets completely loaded it does not shows the data, even though there is data in the page while viewing in the view source.

    Now, when I was searching for the solution, I came to across an article that states that the IE 11 browser does not have MSIE type. So, while searching for the MSIE type in the tablesorter files, I got a function clearTableBody in jquery.tablesorter.mod.js. i.e
    this.clearTableBody = function(table) {
                    if($.browser.msie) {
                        function empty() {
                            while ( this.firstChild ) this.removeChild( this.firstChild );
                        }
                        empty.apply(table.tBodies[0]);
                    } else {
                        table.tBodies[0].innerHTML = "";
                    }
                };

    I worked on it and replaced it with the following code and now its working fine in all the browsers:-
    this.clearTableBody = function(table) {
                  $(table.tBodies[0]).empty();
    }

    But, it seems to me that its not the correct thing to replace the code in the js file. So, can you tell me the correct thing or is there any updated version of the tablesorter.mod.js file that works fine with the IE 11 browser too.

    Thanks,
    Swapnesh
  • @Swapnesh:

    Feel free to edit the file. This is not a project I'm maintaining. I doubt I've touched this code for about 6 years.

    I'm surprised it's held up this long.
  • How can I use your library to get the affect provided by foot able

    I have been using tablesorter for all my apps

    The experience I want if to be able to automatically hide columns on screen resize
    Hidden columns will be shown in the child row

    I want the table to show all columns in full desktop mode but show child rows for mobile devices

    Do I need to redraw the table when the width is reduced to a specific width or can I just add css and child rows below each row

    Tks for yr help

    sum

Comments for this entry have been disabled.