Back to Blog

Get in Touch

PJAX Use Case On Intridea.com

By Andy Wang June 28, 2012 in javascript, pjax

Medium

Background

As a Rails developer I normally spend most of my time on backend development, implementing features and functionalities. I am really confident about my Rails skills for backend work but rarely have I felt any happiness doing frontend work before. But things have changed since working on the new responsive intridea.com. I started some interesting frontend work from this project and fell in love with many UI skills and JS tricks, especially Pjax which I want to talk more about in this post.

What is Pjax?

Pjax is such a fantastic tool. I love this formula which describes Pjax well: pushState + Ajax = Pjax. When you need to store your page state in URL as permanent links, Ajax cannot do it gracefully. Thus, Pjax is a good choice to only update specific parts of web page and allow you to generate permanent links at the same time. Personally, I also like to call Pjax Perfect Ajax.

Pjax Magic in Rails 3.2

Let me show you how we use Pjax to speed up page loading for the current intridea.com website. Firstly, we use a rack middleware rack_pjax which will simply filter the page to respond to pjax-requests accordingly. Ok, add the gem to Gemfile as first step:

 gem 'rack_pjax'

Secondly, we should include this rack application into our Rails stack. This is easy too, just add this line in your config/application.rb file to config the middleware:

 config.middleware.use Rack::Pjax

Thirdly, we install the Pjax jquery plugin to assets/javascripts folder. You can download the Pjax source from this link. As with any other javascript plugin, be sure to include the file in application’s JavaScript manifest file as below:

 //= require jquery
 //= require jquery_ujs
 //= require chosen.jquery.min
 //= require jquery.pjax
 //= .... other js libs

OK, by doing the above three steps of installation and configuration we now have Pjax plugged into our application. It's time to enable the Pjax RULE for our current website. Basically, we want to add a 'data-pjax-container'-attribute to the container in which the HTML content will be updated by the Pjax response. The Pjax data container can be put in any layout or view file in our Rails application. That sounds cool, right? In our case, we only place a Pjax data container in layout as below:

 <!DOCTYPE html>
 <%= html_tag :class => "no-js", :lang => "en" %>
   <%= render "head" %>
   <body id="page">
     <div id="fb-root"></div>
      <div id="main_container">
     <%= render "chromeframe" %>
     <div data-pjax-container>
       <%= render "main_nav" %>
       <div class="wrapper omega <%= params[:controller] %>_container">
         <div id="main" role="main">
           <%= render "flashes" %>
           <%= yield %>
         </div>
         <%= render "footer" %>
       </div>
     </div>
     </div>
     <%= render "javascripts" %>
   </body>
 </html>

Wait, it's not finished yet. Now we enable the Pjax magic for the application. We enabled all links as "Pjax" triggers as below for example:

 $(document).ready(function() {
   $('a').pjax('[data-pjax-container]', {timeout: 3000});
 });

It means, every link on the web page will trigger a Pjax request to the server, then the Pjax data container part will be updated by the Pjax response. Here we set timeout as 3000ms; you can set it higher if you use a custom error handler. Besides timeout, there are a bunch of other options for a Pjax function; they are almost the same as jQuery's $.ajax(), but there are still some additional options, you can take a detailed look at Pjax's doc.

Attentions

We have some javascript code which are binding to some Dom elements in that Pjax data container. For instance, we want to validate our contact form via Javascript, but a Pjax based page reloading will prevent the Javascript validator from working. That's because we only initialize the validator when Document is ready, but a Pjax reloading will not reload the whole document, which means we have to recall the validator again after the Pjax is done. Yeah, Pjax indeed fires two basic events while doing Pjax on your data container: pjax:start and pjax:end. To solve the above javascript validation issue, we need to call that function in Pjax:end callback as well.

 $(document).ready(function() {
   var ApplicationJS = com.intridea.ApplicationJS;

   $('a').pjax('[data-pjax-container]', {timeout: 8000});
   ApplicationJS.validate_contact_form('#contact_form');

   $(document).on('pjax:end', function(){
     ApplicationJS.validate_contact_form('#contact_form');
   });
 });

Similarly, if you want to add a loading indicator upon Pjaxing, then you might need to do something like this:

   $(document).on('pjax:start', function(){
      // this will show an indicator on the <li> tag in navigation.
      ApplicationJS.navSpinner('nav li.active');
   });

Finally, notice that Pjax only works with browsers that support the history.pushState API. Here is a table to show you all related information about popular browsers. When Pjax is not supported in some browser, $('a').pjax('[data-pjax-container]' calls will do nothing but work as normal links. So don't worry about any regarding mess ups.

Have fun playing with Pjax, and please share your feedback and your own use cases with us on Twitter!

Resources

Medium

Andy Wang

Andy has been working on web application development since 2005. From year 2008, he started to be a pure Ruby/Rails engineer. After joined in Intridea in 2011, he became an experienced web system maker with full stack of knowledge including both frontend and backend technologies.
Andy writes tech blog and life blog for many years, he also wrote some company official blogs when needed. Andy is enthusiastic about open source projects and love to share knowledge and passion with people around him.
In Andy's spare time, he is a sports lover, he ever finished 2008 Beijing Marathon full competition and finished a cycling travel in Jul. 2003 from Beijing to Xi'an in China, between which the distance is more than 1300km. When Andy is not learning something, he must be playing basketball or walking around with his Fitzip.

More from our blog

The Problem with PaaS

Read Now →
X

More posts by Andy Wang

Andy Wang

Learn step-by-step how to set up Jenkins CI on EC2 for an internal, continuou...

Andy Wang

Recently, I worked on some interesting features, we use Highcharts and/or Rap...

Andy Wang

### Background As a Rails developer I normally spend most of my time on ba...