Ajax-EE: Sort and Order Data with ExpressionEngine and Ajax part two

Terris Kremer / Posted 5.15.2012

Sort and Order Data with ExpressionEngine and Ajax part two

Last week I wrote about how to sort and order the output of an ExpressionEngine channel entries tag using URL segments as orderby and sort parameters. This week, I’ll show you how to use a bit of jQuery Ajax to perform the sorting without reloading an entire page.

If you missed the first article, I recommend you go back and read it first, as it has some valuable tips for creating fallbacks for users who have JavaScript turned off.

An example of what we’ll be creating in this article is here.

Making it work with Ajax

When we left off with last week’s article, Ajax-EE part one, we had a solid template for ordering and sorting entries using standard links. The code and markup in its entirety should look something like this:

    {if segment_3 == "asc"}
      <th><a href="{path='ajaxee/date/desc'}">Date</a></th>
      <th><a href="{path='ajaxee/title/desc'}">Title</a></th>
      <th><a href="{path='ajaxee/username/desc'}">Author</a></th>
      <th><a href="{path='ajaxee/status/desc'}">Status</a></th>
      <th><a href="{path='ajaxee/date/asc'}">Date</a></th>
      <th><a href="{path='ajaxee/title/asc'}">Title</a></th>
      <th><a href="{path='ajaxee/username/asc'}">Author</a></th>
      <th><a href="{path='ajaxee/status/asc'}">Status</a></th>
  {exp:channel:entries channel="articles" dynamic="no"
    <td>{entry_date format="%M %d, %Y"}</td>
    <td><a href="{path='articles/{url_title}'}">View &raquo;</a></td>

While we could write some jQuery that sifts through the HTMLand sorts the content in place, I’m a big proponent of letting the server do as much of the heavy lifting as possible.

Now that we have data that’s sort-able without the use of Ajax, let’s smooth things out a bit with some jQuery! We still want to load sorted data, but let’s do it without reloading the entire page.

The Ajaxlist

To accomplish this, I’ll need a template that I can load up via Ajax but that only contains the channel entry tags and related markup. Luckily, I can reuse the code and markup I’ve already created for the main template. I’ll create a new template in the “ajaxee” template group called “ajaxlist” and populate it with the entry tags I used earlier:

{exp:channel:entries channel="articles" dynamic="no" orderby="{segment_3}" sort="{segment_4}"}
    <td>{entry_date format="%M %d, %Y"}</td>
    <td><a href="{path='articles/{url_title}'}">{title}</a></td>

The only difference from the main template is that I’ve updated the orderby and sort parameters to use {segment_3} and {segment_4} instead of {segment_2} and {segment_3}. This is because when I make the Ajax call to this template, I’ll need to also reference the template name in my URL.

The Ajax call we make will then look something like this: /ajaxee/ajaxlist/orderby/sort

Next, let’s jump back into the main template and add some classes to the table as well as to the sort links.  Later I can easily select it from the jQuery.

The Sortabletable

For the table tag, I’ll add a class of “sortabletable”:

<table class="sortabletable">

For each sort link, I’m going to add a class of “sort-trigger,” for example:

<a href="{path='ajaxee/date/desc'}" class="sort-trigger">Date</a>

You can read more about the totally 100% valid HTML 5 ‘data-‘ attribute over at HTML 5 Doctor.

In addition to these selector classes, I also need a way to define the orderby and sort values for each link. To do this I’ll use data- attributes in my link tags – one for orderby and one for sort. For example, my Date link will become:

<a href="{path='ajaxee/date/desc'}" class="sort-trigger" data-orderby="date" data-sort="desc">Date</a>

I’ll use these data- attributes to build a full path to the ajaxlist.hml template using Javascript in just a bit. For now, let’s look at my entire updated table header section:

{if segment_3 == "asc"}
  <th><a href="{path='ajaxee/date/desc'}" class="sort-trigger" data-orderby="date" data-sort="desc">Date</a></th>
  <th><a href="{path='ajaxee/title/desc'}" class="sort-trigger" data-orderby="title" data-sort="desc">Title</a></th>
  <th><a href="{path='ajaxee/username/desc'}" class="sort-trigger" data-orderby="username" data-sort="desc">Author</a></th>
  <th><a href="{path='ajaxee/status/desc'}" class="sort-trigger" data-orderby="status" data-sort="desc">Status</a></th>
  <th><a href="{path='ajaxee/date/asc'}" class="sort-trigger" data-orderby="date" data-sort="asc">Date</a></th>
  <th><a href="{path='ajaxee/title/asc'}" class="sort-trigger" data-orderby="title" data-sort="asc">Title</a></th>
  <th><a href="{path='ajaxee/username/asc'}" class="sort-trigger" data-orderby="username" data-sort="asc">Author</a></th>
  <th><a href="{path='ajaxee/status/asc'}" class="sort-trigger" data-orderby="status" data-sort="asc">Status</a></th>

The Fistbump

The final step is to add the jQuery that will make an Ajax call to ajaxlist.html and return output into our table body.  I’ll be sure to include jQuery in the header template first. Then, in the main template, after the table I’ll add the following jQuery code. Read through the // code comments step by step to get a good sense of what the script is doing.

<script type="text/javascript">
    // Once the document is ready
      // remember the table body as ‘lz’
      var lz = $('.sortabletable tbody');
      // remember the sort triggers as ‘st’
      var st = $('.sort-trigger');
      // then when a sort trigger is clicked...
        // remember it's data-orderby and data-sort values as ‘stOrderby’ and ‘stSort’
        var stOrderby = $(this).attr('data-orderby');
        var stSort = $(this).attr('data-sort');
        // build a full path using stOrderby and stSort
        var stTarget = '/ajaxee/ajaxlist/'+stOrderby+'/'+stSort+'/';
        // load up the ajaxlist template using stTarget and drop it into the lz
        // if this links data-sort is asc
        if( stSort == 'asc' ){
          // reverse it so it sorts desc next time
          $(this).attr('data-sort', 'desc');
        // otherwise it must be desc so 
        } else {
          // reverse it so it sorts asc next time
          $(this).attr('data-sort', 'asc');
        // and, finally, prevent the default link behavior
        return false;

This script loops through each link with a class of “.sort-trigger” and attaches an onclick function to it. Then, when the link is clicked, the function builds a full path to the ajaxlist template using the links’ data-orderby and data-sort values (e.g. /ajaxee/ajaxlist/title/desc). Next it loads up the ajaxlist template using the built path via Ajax and drops it into the table body. Last but not least, the function switches the clicked link’s data-sort value so that the next time the user clicks that link the data will be sorted in the opposite direction.

Now, when we click on a table header link, we should see that the table is updated with sorted, ordered data.

Pump fist, say, “Yeah!” We’re done. That’s how we sort and order ExpressionEngine data on the fly with Ajax.

Questions? Let me know in the comments and I’ll do my best to help you out.

Terris Kremer

Front-end developer at Q Digital Studio

Terris Kremer is a front-end developer at Q Digital Studio. While he may joke that both front- and back-end developers are dweebs, Terris really does make development look cool. For Terris, work is a game that he can (and does) play all day long.