Behavior: OrderBy

posted Jan 19, 2012, 7:31 AM by Eric Patrick   [ updated Jul 20, 2015, 7:50 AM by Philip Raath ]

QBO 3's qbo.OrderBy.js is a behavior plugin that enables sorting an HTML table by clicking on column headers. Unlike the MooTools HtmlTable class, this plugin simply raises an 'order' event with the name of the column to order by. The qbo3.AbstractObject listens for 'order' events, and will redraw a table accordingly.

To use this behavior:
  • Ensure your table includes a table, thead, tbody, and tfoot elements,
  • Ensure you choose an appropriate tr element inside the thead element to add the OrderBy behavior to,
  • Optionally rename or disable individual columns (th) tags within your OrderBy row
Example:

<table class="grid">
  <thead>
    <tr>
      <td colspan=3>My Title Here</td>
    </tr>
    <tr data-behavior="OrderBy">
      <th>Column1</th>
      <th>Column2</th>
      <th>Column3</th>
    </tr>
  </thead>
  <tbody> ... </tbody>
  <tfoot> ... </tfoot>
</table>


The behavior will listen for mouse clicks on the TR tag, and raise an 'order' event with the name of the column determined by the HTML of the TH tag ('Column1', 'Column2', or 'Column3' in the example above).

If you have a column where the label does not match the SQL table column name, you can add a data-orderby-column attribute to override it:

<th data-orderby-column="Property.Address">Address</th>

Note that you do not need to specify an data-orderby-column simply to remove spaces; spaces are stripped from the th tag's html automatically by the OrderBy behavior.

If you have a column that should not be sortable, you can "disable" by adding a data-orderby-disabled attribute:

<th data-orderby-disabled="true">Column2</th>

It is useful to track the "current" sort order so that we can show the user which column is currently the sorted column. This is done by adding a data-orderby-current attribute to the TR tag.  

<tr data-behavior="OrderBy" data-orderby-current="Column1">

Telling the OrderBy behavior what the current column is results in adding an 'orderAsc' class being added to the column. If the current order by begins with a '-' (e.g. '-Column1'), an 'orderDesc' class is added instead.

When the user clicks on a column, if it is already the current sort column, the behavior assumes the user wants to reverse the sort, and will append a '-' to the current value.

However, we want to data-drive the sort order, rather than hard-coding it to 'Column1'. Using XSLT, we do the following:
  • Add an <xsl:param name="OrderBy"/> to the XSLT, and
  • Set the data-orderby-current="{$OrderBy}"
So what happens is:
  • The user clicks on Column3,
  • An order event is fired with {OrderBy: 'Column3'} as the argument,
  • qbo3.AbstractObject merges the order event argument with it's current data payload, replacing OrderBy: 'Column1' with OrderBy: 'Column3',
  • The server processes the request, passing each request parameter as a parameter to the XSLT (including OrderBy=Column3),
  • The OrderBy behavior is applied to the results, adding either the 'orderAsc' or 'orderDesc' class to the Column3 TH tag.
The final HTML looks something like this:

<table class="grid">
  <thead>
   <tr>
      <td colspan=3>My Title Here</td>
   </tr>
   <tr data-behavior="OrderBy" data-orderby-current="{$OrderBy}">
     <th data-orderby-column="Column1">Column 1</th>
     <th data-orderby-disabled="true">Column2</th>
     <th>Column3</th>
   </tr>
   </thead>
   <tbody> ... </tbody>
   <tfoot> ... </tfoot>
</table>

As of the time of writing, the qbo3.css class defines the orderAsc and orderDesc classes as follows:

/* .orderAsc: Use for sortable columns to indicate the current sort. E.g. <th class="orderAsc">Status</th> */
.orderAsc {
background: url(../images/icon.up.gif) no-repeat right;
}
/* .orderDesc: Use for sortable columns to indicate the current sort. E.g. <th class="orderAsc">Status</th> */
.orderDesc {
background: url(../images/icon.down.gif) no-repeat right;
}

This adds an up arrow or down arrow on the right side of the column. No extra HTML markup is required.

Multi Column Sorting

The OrderBy behavior also allows sorting by multiple columns. 

The basic steps are:
  1. Click on a column to select the 'anchor' column, i.e., the first value in the OrderBy string.
  2. Ctrl+Click on another column in order to append another OrderBy value.
    • You will notice that the two selected column headers are now prepended with numeric values to demonstrate the ordering.
  3. Ctrl+Click the second column again to toggle Order Ascending or Order Descending on that column.
    • Any column in the multi sort selection (including the anchor) can be toggled between Ascending and Descending at any time
  4. Use a normal Click (not Ctrl+Click) at any time to exit the multi sort behavior
Use Case: 
  • Perhaps a manager has a list of SmartWorklistMember items, and wants to view the following:
    • All items assigned to a Foreclosure team
    • The most recently completed items for that team
  • The manager would then do the following:
    1. Click on the Team column to set the anchor:
    1. Ctrl+Click on the Completed column:
      1. Notice that the Team and Completed column headers are now indicated in yellow, and that their relative ordering is indicated with numbers.
    1. Ctrl+Click on Completed a second time, in order to place the most recently completed items at the top of the list for the Foreclosure Team:
      • Notice that the Order Descending arrow is now shown on the Completed column header.
  • If the manager then wished to perform a different search:
    • Click (not Ctrl+Click) on any column header to reset.
In order to indicate which columns are included in the current multi sort selection, the following CSS is used:
/* .multiSort: Use for sortable columns to indicate that multi column sorting is in effect. E.g. <th class="orderAsc multiSort">Status</th> */
.multiSort{
    color:yellow !important;
}
Comments