The Joy of Tables On Cows

June 20th, 2008

On June 12th MooTools 1.2 was released, to great rejoicing. It’s a release that really sets MooTools apart with better Fx, more browser compatibility effort, and a jaw dropping element storage feature. That means it’s time to update the table sort script I’ve blogged here before (The Joy of a Minimal, Complete Javascript Table Sort and The Joy of an Optimized, Complete Javascript Table Sort). This release does more than just port, and also adds a few features:

  • Sorts more out of the box:
    • strings
    • numbers
    • decimal currency (12.34, 4.50)
    • dates (YYYY-MM-DD, YYYY-M-D)
    • relative dates (1 day ago, 38 years ago)
    • disk memory (1.75 MB, 34 KB, 8 TB)
  • Passes the matcher into the conversion_function for re-use.
  • Classes set for forward and reverse sorting th tags.
  • A “don’t sort” class.
  • It’s on github!
  • Integration with the brand new pagination library.

Oh yeah, and that. There’s now a pagination library supporting all the same things like expanding rows. It’ll do multiple pagination link areas and drop offset and cut-off numbers into the DOM. Let’s take a look.

The Old: Reviewing SortingTable

SortingTable doesn’t need any wonky DOM rewrite, that’s one of it’s best perks. Just use a thead and tbody, and make proper use of th.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<table cellpadding="0" cellspacing="0" id="sort_this">
  <thead>
    <tr>
      <th>a header</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>a value
    </tr>
    <tr>
      <td>another value</td>
    </tr>
  </tbody>
</table>

To sort this table you could use the most simplistic of initializations:

1
new SortingTable( 'sort_this' );

These are the default settings that are assumed:

1
2
3
4
5
6
7
new SortingTable( 'sort_table', {
  zebra: true,                        // Stripe the table, also on initialize
  paginator: false,                   // Pass a paginator object
  dont_sort_class: 'nosort',          // Class name on th's that don't sort
  forward_sort_class: 'forward_sort', // Class applied to forward sort th's
  reverse_sort_class: 'reverse_sort'  // Class applied to reverse sort th's
});

So if you wanted to not sort a given column, just add class=”nosort” and it’ll be ignored. You could also change that to any other class. The same goes for the classes forward_sort and reverse_sort.

The passing of conversion_matcher into the conversion_function makes it more DRY to use regex on a td for sort. Take a look at the date sorter:

1
2
3
4
5
6
7
8
      // YYYY-MM-DD, YYYY-m-d
      { matcher: /(\d{4})-(\d{1,2})-(\d{1,2})/,
        conversion_function: function( row ) {
          var cell = $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
          cell = this.conversion_matcher.exec( cell );
          return new Date(parseInt(cell[1]), parseInt(cell[2], 10) - 1, parseInt(cell[3], 10));
        }
      },

We get to re-use that regex right in the conversion_function.

That’s it for incremental changes to SortingTable. PaginatingTable is the thing to introduce.

The New: Introducing PaginatingTable

To paginate a table you’ll need to add one DOM element:

1
<ul id="sort_table_pagination"></ul>

And then paginating the simple table provided above would look like:

1
new PaginatingTable( 'sort_table', 'sort_table_pagination' );

That’s the simplest way to go. A more complex pagination might involve two paginators as well as displaying offsets and cutoffs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<ul id="sort_table_pagination"></ul>
Now showing items <span id="offset"></span> - <span id="cutoff"></span>
<table cellpadding="0" cellspacing="0" id="sort_this">
  <thead>
    <tr>
      <th>a header</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>a value
    </tr>
    <tr>
      <td>another value</td>
    </tr>
  </tbody>
</table>
<ul id="sort_table_bottom_pagination"></ul>

To start this up:

1
2
3
4
5
6
new PaginatingTable( 'sort_table', ['sort_table_pagination', 'sort_table_bottom_pagination'], {
  per_page: 3,         // Only 3 items per page, please
  current_page: 2,     // Start on page 2
  offset_el: 'offset', // Use this id for offset numbers
  cutoff_el: 'cutoff'  // And this id for cutoffs
});

Swank. This will paginate, but you don’t get any sorting or zebra striping. That’s still tied to SortingTable, and you’ll need to use them together.

PaginatingTable also provides update_pages on a given instance- so if you add rows to a table you can have the pagination update itself.

Will It Blend? SortingTable and PaginatingTable Together

SortingTable will accept a PaginatingTable object and use it to reset to the first page when you sort. Just pass it in:

1
2
3
new SortingTable( 'sort_table', {
  paginator: new PaginatingTable( 'sort_table', 'sort_table_pagination' )
});

If you have expanding rows, you’ll need to tell both SortingTable and PaginatingTable about it:

1
2
3
4
new SortingTable( 'sort_table', {
  details: true
  paginator: new PaginatingTable( 'sort_table', 'sort_table_pagination', { details: true } )
});

You can check out the example to see this in action, and get the javascript from github. A big thanks to all the people that wrote conversion functions and made tweaks to this script, and kept it crawling from an example into a more capable library. Enjoy!

By Matthew Beale
13 comments
  1. John Baughman at June 20th, 2008 at 02:27 PM

    Very cool! Once we get the sorting working (again), we’re going to look into this pagination. Awesome work!

  2. Brady at July 10th, 2008 at 01:41 AM

    In the example, i don’t think the sorting of dates works correctly. It sorts by month and date correctly, but the years do not go in chronological order. I’m not sure if this is how it is suppose to be, but felt i should bring it to your attention.

  3. Matthew Beale at July 10th, 2008 at 11:53 AM

    Hey Brady- No it’s not how it should be, nice catch. Off the top of my head I bet it’s b/c the date sorter converts the innerText to Javascript Date objects- which in turn may not go past the epoch or something.

    I’ll push a rev up to github and update the blog post when I get out a fix.

  4. Evan at July 11th, 2008 at 03:26 PM

    Thanks for the script came out at just the right time for me.

  5. Hans at July 22nd, 2008 at 06:43 PM

    This is truly awesome. Thank you.

    One question though: I am attempting to add alphabetic pagination and I would appreciate some pointers: How would you do it? Thank you.

  6. Andre at July 30th, 2008 at 10:10 PM

    Thanks a lot for your effort, this was exactly what i needed. cheers!

  7. Mike at August 11th, 2008 at 10:36 AM

    Question:

    Will this work if I remove all tr elements from the table and then reload new ones using json data from ajax request?

  8. Matthew Beale at August 12th, 2008 at 10:53 AM

    Hey Mike-

    The javascript object will not be attached to the DOM element once you remove the DOM element :-). The column sort will still work if you drop and add rows. If you drop and remove columns while using the paginator you’ll need to call update_pages to update the links and display.

    Hope it helps! -Matt

  9. Fabian Tollenaar at August 17th, 2008 at 01:02 PM

    Hi people,

    Thanks Matt, this is a great sorting class. I started to work with this class in the latest version of the cms web app for my clients. But before I did so, I modded it a bit so it has highlight (mouse over) effects on each row within the table.

    see here for the code: http://blog.dotbrilliance.nl/files/ click on Sort.Mootools!

    thanks again,

    Fabian

  10. Mike at September 8th, 2008 at 05:07 PM

    Not sure whether this is a but or not but…

    This works in IE 7 and 8 new PaginatingTable( ‘sort_table’, ‘sort_table_pagination’, { per_page: 3});

    Won’t work in IE 7 and 8: new PaginatingTable( ‘sort_table’, [‘sort_table_pagination’, ‘sort_table_bottom_pagination’], { per_page: 3});

  11. Jeff at September 12th, 2008 at 11:17 AM

    Is there a way to have the first sort be descending on certain columns?

    Thanks,

    Jeff

  12. Barbara at September 12th, 2008 at 11:22 AM

    Hi Matt, Thanks for explaining how to do this. I love it and your instructions are great! I am having a problem that I also think I saw in the last example that uses paging and sorting.

    1. Sort on shortString 2. Go to page 10 3. Sort on int (brings you back to page 1) 4. Hit the ”>>” to go to the next page

    This takes you to page 11. How do I get the arrow buttons to update with the new sort? Thanks a lot.

  13. Steve at September 12th, 2008 at 06:54 PM

    Hi Barbara,

    It’s simple. In the sorting table class, find where it resets the pagination. It is using to_page(1). Just switch that to call update_pages() instead and the paginator list nodes will update correctly

  14. tr0y at September 16th, 2008 at 10:55 PM

    Great class, been looking for something like this for 1.2, and this is the first thing I have found that seems stable enough for production. Thanks much, saved me a ton of trouble :)

Comments are closed for this article.