Photo from Chile

jQuery Auto-Filtering Table

I've been using jQuery for about a year now and I must admit that pretty much any JavaScript that I wrote prior to that looks ugly to me now. I know I'm nowhere near the first person to say this, but if you write JavaScript and you aren't using jQuery, you should check it out. Now.

Anyway, I wanted to show you how easy it is to do something cool with jQuery. The next thing I'll admit is that much of what I'm doing with jQuery involves using existing plugins written by other, more seasoned JavaScripters than me. But enough talk, here's the table:

Country Province/State City
Canada Alberta Calgary
Canada Alberta Edmonton
Canada British Columbia Vancouver
Canada British Columbia Victoria
Canada Ontario Ajax
Canada Ontario Kingston
Canada Ontario London
Canada Ontario Ottawa
Canada Ontario Toronto
United States California Los Angeles
United States California San Francisco
United States California San Jose
United States Texas Dallas
United States Texas Houston
United States Texas Lubbock

You'll notice that you can sort the table by any of the columns, in both ascending and descending order, and even by multiple columns if you hold down the Shift key while clicking. That sortable behaviour, and the nice zebra striping is all part of the awesome tablesorter plugin, written by Christian Bach.

Now see what happens when you click on a Country or a Province/State in the table. That's right, the table filters itself based on your selection. Clicking on the same Country or Province/State removes the filter. Once the table is filtered you can still sort on any or all of the columns. This filtering functionality is provided by the only slightly less awesome uiTableFilter plugin, written by Greg Weber.

All I had to do was write a few lines of code to implement the plugins and set up the events to be fired when clicking the data in the table:

view plain print about
1<script type="text/javascript">
2$(document).ready(function() {
3    $table = $("#myTable")
4        .tablesorter({widthFixed: true, widgets: ['zebra']});
5    FilterText = "";
6    ColumnArray = ["Country","Province/State"];
7    for (i=0;i<ColumnArray.length;i++) {
8        $("#myTable tbody tr").find("td:eq(" + i + ")").click( function() {
9            clickedText = $(this).text();
10            FilterText = ((FilterText == clickedText) ? "" : clickedText );
11            $.uiTableFilter( $table, FilterText, ColumnArray[i]);
12        });
13    }

First I make the table, which has an id of "myTable", sortable using the tablesorter plugin. Next I create a couple of local variables:

  • FilterText will hold the current value that is being used to filter the table.
  • ColumnArray is an array of column headings that I want to be clickable.

I then loop through the ColumnArray assigning a click event to the proper column of each table row. The click event captures the text that was clicked on and saves it to clickedText. clickedText is then compared to FilterText to determine whether to apply a new filter (if a new value was clicked) or remove the filter (if the same value was clicked). Finally the new filter is applied to the proper column of the table.

And there you have it, a pretty neat trick accomplished with very few lines of JavaScript Code.

Regarding the tablesorter plugin, it truly is awesome and can do a lot more that I have described in this post. In addition to being incredibly configurable, it also has a paging addon that gives you a full featured paging control for your table.

The paging plugin for tablesorter is mighty impressive as well!
# Posted By John Whish | 10/2/08 7:26 AM
That's slick. jQuery saved my life.
# Posted By John Allen | 10/2/08 8:18 AM

# Posted By velcrow | 10/2/08 9:30 AM
I have pager also added to my table. when i tried filter, its filtering only the visible page rows. I want to filter the entire rows in table.
# Posted By Satheesh | 10/23/09 10:57 AM
Do you know if tablesorter will work with a table filled by the DB?

# Posted By Lena | 11/4/09 9:19 AM
pretty cool use case and transformation to the click event instead of using input field
# Posted By dcdieci | 12/4/09 6:44 PM
is there a way to make the uiTableFilter work in a cascade fashion with multiple inputs? I mean if I click on california and then click on united states, it should show only united states and california (and not texas)
# Posted By sf45 | 5/27/10 2:06 PM
I have 2 rows with similar text (Es. 1° record: 1° column with text "service", 2° column with text "good", 2° record: 1° column with text "", 2° column with text "good service")
when I click on the first record over text "service" I expect only the 1° record but I have the 1° and 2° because the text in second column contains "service" too.
Sorry for my english but I hope that you understand my problem and you can solve it.
# Posted By Matteo Cesarotti | 8/26/10 2:45 AM
It appears that the line ...
$.uiTableFilter( $table, FilterText, ColumnArray[i]);
may not be passing a valid ColumnArray element. In particular, if you have the same text in a different column, the respective row will be included in the filtered results.

I changed the code to the following, which seemed to work properly ...
      for (i=0;i<ColumnArray.length;i++) {
         $("#first_table tbody tr").find("td:eq(" + i + ")").click( function() {
            clickedText = $(this).text();
            FilterText = ((FilterText == clickedText) ? "" : clickedText );
ColumnHeader = ColumnArray[this.cellIndex];
            $.uiTableFilter( $table, FilterText, ColumnHeader);
# Posted By baggerone | 8/30/10 2:40 PM
Hi Baggerone,
thank you, your code work properly.
Now to solve the problem I have splitted the code for each column
$("#myTable tbody tr").find("td:eq(" + 0 + ")").click( function() {
clickedText = $(this).text();
FilterText = ((FilterText == clickedText) ? "" : clickedText );
$.uiTableFilter( $table, FilterText, "MyColumn");
but your code is better.
# Posted By Matteo Cesarotti | 8/31/10 2:34 AM
Thank you very much for this excellent bit of code. You really helped me out :).
I have one question though. I have a row with dates and I would like to filter on those. Now when I have for example "Aug. 1, 2010" and "Aug. 31, 2010" in that row, it shows both when I click on "Aug. 1, 2010". This can be solved by formatting the date such that it has a 0 in front of the 1-digit days, but I prefer the non-zero version. Do you have any idea how this could be solved?
# Posted By Heleen | 9/3/10 9:08 AM
Hey, this is pretty great. But there's a little bug that I fixed and I thought I'd share.

In the example presented above, if you sort by city and then filter to only Canada you'll notice that the background ("zebra") striping is wrong. It happens because the tablesorter plugin doesn't get the message that its data has been updated.

Here's sample code with the appropriate fix in place :
$table = $("#myTable")
.tablesorter({widthFixed: true, widgets: ['zebra']});
FilterText = "";
ColumnArray = ["Country","Province/State"];
for (i=0;i<ColumnArray.length;i++) {
$("#myTable tbody tr").find("td:eq(" + i + ")").click( function() {
clickedText = $(this).text();
FilterText = ((FilterText == clickedText) ? "" : clickedText );
$.uiTableFilter( $table, FilterText, ColumnArray[i]);

Hope someone out there finds this handy! Thanks again for the great post.

# Posted By Matt Bosworth | 1/7/11 2:31 PM
Bleh, so much for formatting ...

And I missed a #

So here's the short version. Add the following line after the call to $.uiTableFilter(...) :


Hope that helps,
# Posted By Matt Bosworth | 1/7/11 2:36 PM
Thanks for the tip, Matt!
# Posted By Bob Silverberg | 1/7/11 3:24 PM
Am I missing something here?

All I can see is a sorter plugin - a filter plugin provides a drop-down list on the field title, allowing you to select specific results...this does not do that, and is incorrectly named.
# Posted By Rick | 1/17/11 6:07 AM
thank you....God bless YOU always
# Posted By jake young | 1/30/11 7:13 AM
First of all, thank you for this.
How to make subtotal of values of filtered rows.
# Posted By Vladimir | 6/20/11 8:34 AM
I really like this. But have you tried it with the new version of tablesorter using child/collapsible rows? My experiment with it shows uitablefilter gets confused when there are child rows.
# Posted By Rosina | 11/7/11 7:32 PM
Filtering a table with repeat values in different columns:

With a table of repeat values, eg naughts and crosses as above. Is there a way to code tablefilter to return just row 1 if I click on the X in column A, rather than getting rows 1,3,4, i.e. all rows with an X?
# Posted By GAL | 1/9/12 5:41 AM