Ajax-EE: Sort and Order Data with ExpressionEngine and Ajax part two brought to you by META Q
Interior Ad 3 brought to you by The META Q

Ajax-EE:
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:

{embed='site/header'}
<h2>Articles</h2>
<table>
<thead>
  <tr>
    {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>
    {if:else}
      <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>
    {/if}
  </tr>
</thead>
<tbody>
  {exp:channel:entries channel="articles" dynamic="no"
  orderby="{segment_2}"
  sort="{segment_3}"
  }
  <tr>
    <td>{entry_date format="%M %d, %Y"}</td>
    <td>{title}</td>
    <td>{author}</td>
    <td>{status}</td>
    <td><a href="{path='articles/{url_title}'}">View &raquo;</a></td>
  </tr>
  {/exp:channel:entries}
</tbody>
</table>
{embed='site/footer'}

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}"}
  <tr>
    <td>{entry_date format="%M %d, %Y"}</td>
    <td><a href="{path='articles/{url_title}'}">{title}</a></td>
    <td>{author}</td>
    <td>{status}</td>
  </tr>
{/exp:channel:entries}

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>
{if:else}
  <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>
{/if}

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
    $(document).ready(function(){
     
      // 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...
      st.click(function(){
       
        // 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
        lz.load(stTarget);
       
        // 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;
       
      });
    });
  </script>

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's avatar

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.

Posted

5.15.2012

Categories

Code > ExpressionEngine > jQuery

Tags

5 comments >

What others are saying

Niall Thompson

Great article and just what i’ve been looking for. Do you think there is a way to animate the sorting?

Nathan

How can this be implemented with paginated results?

The site I’m working on is on EE 1 currently, and will be upgraded by the end of summer, but I’d love to make this work in the meantime.

Thanks!

Jared

So I’ve followed your tutorial pretty closely, and it works, but only on the first click of one of the sort trigger links. After you click it, it does it’s thing correctly and pulls the template via Ajax. The second time you click the trigger, it loads it sans-Ajax and reloads the page with the fallback, full URL method. Any ideas you can throw my way on figuring this out?

Terris Kremer

Hi Jared, do you have an example set up that I can look at? It would be helpful for me to see exactly what you’ve got going on.

Thanks!

Mike

This helped a lot today, thanks!


Speak your mind