Favour PJAX over dynamically loaded partial views

How to use Pushstate and PJAX with ASP.NET MVC to reduce the number of HTTP requests and improve site performance.

Back to blog

I recently worked on an ASP.NET MVC project with a tabbed user interface that uses jquery/AJAX to dynamically load tab content via a partial view in order to save on page load and initialization times. It seems to be a reasonably widespread technique – the detail varies slightly but the implementation is always something like,

The jquery UI tab control even supports partial content loading out of the box with ‘AJAX mode’ so you don’t even have to write any javascript.

There is a better technique for loading only part of a page that has the following benefits over dynamically rendering partials,

  • Standard permalinks to content – for example, with a tabbed UI, each tab would have its own unique url
  • Maintains browser history when partial content is loaded. Means the back/forward buttons on the browser work correctly
  • Supports page titles
  • Doesnt require specific controller methods to render partial content
  • Degrades to full page loads if the browser doesn’t support HTML 5

The technique makes use of AJAX calls and an HTML 5 method on the window.history object called ‘pushState’. Pushstate is a way to change the browser url (and insert the url into the browser history) without refreshing the page. In the Chrome console if you enter,

Chrome will change the url in the title bar to [yourdomain]/foo.html but wont refresh the page. If you look in the browser history, you will see an entry for [yourdomain]/foo.html.

Its not entirely trivial to take advantage of pushstate in a web application. At a minimum you need to hijack links to issue ‘pushstate requests’ on compatible browsers, issue an AJAX request to a URL, and insert the results into the DOM. Also nice to handle timeouts and provide extension points for displaying loading graphics, etc.

Fortunately, pjax is a lightweight jquery plugin that does this for us. Below is a simple tabbed UI I created that makes use of PJAX to load tab content.

Demo application

If you open the network panel of Chrome developer tools, you will see that the first request to a page loads all the content, stylesheets, images, and scripts – about 465k of content. Click on a tab and chrome issues a single GET request and the response is the content of the tab – about 530 bytes. Also note that your history will be updated with the tab url and page title.

The github page describes a few different setup options for pjax. The simplest way is to call pjax on all relevant links passing in a div identifying the parent id of the content area.

So in the body section of my layout page I included,

And the following script to initialize pjax on the tab ui links,

On the server side, pjax assumes that the server returns content HTML only when the x-pjax header is present in the HTTP request. This is easy to implement in a simple mvc app. In viewstart, check for the existence of the x-pjax header and switch to a different layout page that just renders a title (required by pjax) and the body content only.

_viewStart.cshtml,

_PjaxLayout.cshtml,

You can include script code to run on jquery document ready by also attaching to the pjax:success event,

The big limitation with this approach is that it doesnt support layout views with multiple MVC sections. You would have to extend or monkey patch the pjax library to match rendered sections with specific elements in the DOM.

As you read this far, you should follow me on twitter here.