Sunday, January 25, 2009

Sorting Textbox contents with jQuery TableSorter

I recently needed to add client-side sorting to a table having one column of textboxes. I wanted the client to have the same sorting capabilities for this column as they did for the rest of the columns in the table.

Although I love the jQuery TableSorter plugin – the built-in parsers don’t really accommodate this type of thing.

After a bit of javascript debugging, I realized as long as there wasn’t any other markup in the cell besides the textbox itself – it’d be pretty simple using a bit of jQuery to extract the value.

This is the custom parser I came up with:

$.tablesorter.addParser({
id: "textbox_text",
is: function(s) {
return false;
},
format: function(s) {
return $($.trim(s)).val().toLowerCase();
},
type: "text"
});
The format function takes the raw html of the input element passed in via the s argument and basically just uses jQuery to extract the val().

Just remember the is function always returns false so you have to explicitly set the parser on a particular column like this:
$('#table1').tablesorter({
headers: {
0: { sorter: "textbox_text" }
}
});
The cool thing is that although this illustrates the concept of extracting text from an input element, you could use this technique to obtain a value/attribute/childnode/etc from any type of element.

7 comments:

  1. Hi Scott, have you tested this? I cant get it to work, which is rather strange. So far Im guessing it has to do with values being processed when the table first loads. So any text you enter in the text box later is just ignored. But if you were to assign value [input value='x'] then it does work...
    Nick

    ReplyDelete
  2. Hey Nick-
    The tablesorter plugin stores the table data on the client when you initially call the .tablesorter() method. If you want the data store to be updated (like when you change the contents of your textboxes) - you'll want to hook into the change() events of your textboxes - and call the tablesorter's trigger("update") method like this:

    $("input[@type='text']").change(function() {
    $('#table1').trigger("update");
    });

    You can read more about it here:
    http://tablesorter.com/docs/example-ajax.html

    Hope it helps-

    ReplyDelete
  3. Scott, thank you!

    I found the problem. Basically I ran out of options and out of desperation tested it on IE and it worked just like it was supposed to. The problem is with mozilla [for some very strange and obscure reason]. But since Im developing for ie its safe to flag the issue.

    Nick

    ReplyDelete
  4. Nick-
    I just did some comparison testing on IE7 vs FF3 and I see exactly what you are talking about. I'd never noticed the issue with FF and the trigger("update") method not working correctly. Thanks for bringing it to my attention. I may contact the tablesorter plugin developer and see if they can shed any light on the issue.

    ReplyDelete
  5. FWIW - I've emailed the author and also posted on the jquery plugins google group to see if anyone has run across the issue with FF3 before..

    ReplyDelete
  6. I have tried to follow your example, but it's possible I lack some skills in jQuery or javascript in general.
    I am trying to write a format-function that can extract the TEXT from a setup such as this:
    (div)(a href='something_1')TEXT(/a)(/div) (all of that is inside the TD in the column that is causing my problems)

    (I had to use () in stead of <> in this post)
    Can anyone help me with the format-function to pick up the TEXT, so I can stop it sorting on the link in the href? :)

    ReplyDelete
  7. It does not work in Firefox.
    Another option you can override textExtraction as in the example
    http://tablesorter.com/docs/example-option-text-extraction.html

    // call the tablesorter plugin
    $("table").tablesorter({
    // define a custom text extraction function
    textExtraction: function (node) {
    // iterates all childs elements inside td and return data from the last child
    if (node == null) { return null };
    node = $(node);
    while (node.children().length > 0) {
    node = node.children(":first");
    }
    if (node[0].tagName.toUpperCase() == "INPUT")
    {
    if (node.attr("type").toUpperCase() == "CHECKBOX")
    {
    return node.attr("checked").toString();
    }
    else
    {
    return $.trim(node.val());
    }
    }
    else
    {
    return $.trim(node.text());
    }
    }
    });

    When you update data in a INPUT don't forget to update tablesorter:

    $("table").trigger("update");

    ReplyDelete