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!

Thanks for reading and come again, -Matt

8 Responses

  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

Leave a Reply