pjax
.--.
/ \
## a a
( '._)
|'-- |
_.\___/_ ___pjax___
."\> \Y/|
/ \ \_\/ / '-' /
| --'\_/|/ | _/
|___.-' | |`'`
| | |
| / './
/__./` | |
\ | |
\ | |
; | |
/ | |
jgs |___\_.\_
`-"--'---'
pjax = pushState + ajax
pjax is a jQuery plugin that uses ajax and pushState to deliver a fast browsing experience with real permalinks, page titles, and a working back button.
pjax works by grabbing html from your server via ajax and replacing the content of a container on your page with the ajax'd html. It then updates the browser's current url using pushState without reloading your page's layout or any resources (js, css), giving the appearance of a fast, full page load. But really it's just ajax and pushState.
Overview
pjax is not fully automatic. You'll need to setup and designate a containing element on your page that will be replaced when you navigate your site.
Consider the following page.
Go to next page.
We want pjax to grab the url /page/2 then replace #pjax-container with whatever it gets back. No styles or scripts will be reloaded and even the h1 can stay the same - we just want to change the #pjax-container element.
We do this by telling pjax to listen on a tags and use #pjax-container as the target container:
$(document).pjax('a', '#pjax-container')
Now when someone in a pjax-compatible browser clicks "next page" the content of #pjax-container will be replaced with the body of /page/2.
Magic! Almost. You still need to configure your server to look for pjax requests and send back pjax-specific content.
The pjax ajax request sends an X-PJAX header so in this example (and in most cases) we want to return just the content of the page without any layout for any requests with that header.
Here's what it might look like in Rails:
def index
if request.headers['X-PJAX']
render :layout => false
end
end
If you'd like a more automatic solution than pjax for Rails check out Turbolinks.
Installation
bower
$ bower install jquery-pjax
Or add jquery-pjax to your apps bower.json.
"dependencies": {
"jquery-pjax": "latest"
}
standalone
pjax can be downloaded directly into your app's public directory - just be sure you've loaded jQuery first.
curl -O https://raw.github.com/defunkt/jquery-pjax/master/jquery.pjax.js
WARNING Do not hotlink the raw script url. GitHub is not a CDN.
Dependencies
Requires jQuery 1.8.x or higher.
Compatibility
pjax only works with browsers that support the history.pushState API. When the API isn't supported pjax goes into fallback mode: $.fn.pjax calls will be a no-op and $.pjax will hard load the given url. This mode targets the browser requirements of the jQuery version being used.
For debugging purposes, you can intentionally disable pjax even if the browser supports pushState. Just call $.pjax.disable(). To see if pjax is actually supports pushState, check $.support.pjax.
Usage
$.fn.pjax
Let's talk more about the most basic way to get started:
$(document).pjax('a', '#pjax-container')
This will enable pjax on all links and designate the container as #pjax-container.
If you are migrating an existing site you probably don't want to enable pjax everywhere just yet. Instead of using a global selector like a try annotating pjaxable links with data-pjax, then use 'a[data-pjax]' as your selector.
Or try this selector that matches any links inside a
$(document).pjax('[data-pjax] a, a[data-pjax]', '#pjax-container')
When invoking $.fn.pjax there are a few different argument styles you can use:
$(document).pjax(delegation selector, options object)
$(document).pjax(delegation selector, container selector, options object)
The first argument must always be a String selector used for delegation.
The second argument can either be a String container selector or an options object.
This example uses the current click context to set an ancestor as the container:
$(document).on('click', 'a[data-pjax]', function(event) {
var container = $(this).closest('[data-pjax-container]')
$.pjax.click(event, {container: container})
Submits a form via pjax. This function is experimental but GitHub uses it on Gist so give it a shot!
$(document).on('submit', 'form[data-pjax]', function(event) {
$.pjax.submit(event, '#pjax-container')
$.pjax({url: url, container: '#pjax-container'})
pjax fires a number of events regardless of how its invoked.
All events are fired from the container, not the link was clicked.
pjax:start - Fired when pjaxing begins.
pjax:end - Fired when pjaxing ends.
pjax:click - Fired when pjaxified link is clicked.
pjax:beforeSend - Fired before the pjax request begins. Returning false will abort the request.
pjax:send - Fired after the pjax request begins.
pjax:complete - Fired after the pjax request finishes.
pjax:success - Fired after the pjax request succeeds.
$(document).on('pjax:send', function() {
$(document).on('pjax:complete', function() {
Another protip: disable the fallback timeout behavior if a spinner is being shown.
$(document).on('pjax:timeout', function(event) {
// Prevent default timeout redirection behavior
Check if your favorite server framework supports pjax here: https://gist.github.com/4283721
Layouts can be forced to do a hard reload assets or html changes.
First set the initial layout version in your header with a custom meta tag.
Then from the server side, set the X-PJAX-Version header to the same.
response.headers['X-PJAX-Version'] = "v123"
$('a[data-pjax]').pjax('#pjax-container')
$('a[data-pjax]').live('click', function(event) {
$.pjax.click(event, '#pjax-container')
$(document).pjax('a[data-pjax]', '#pjax-container')
$(document).on('click', 'a[data-pjax]', function(event) {
$.pjax.click(event, '#pjax-container')
$ git clone https://github.com/defunkt/jquery-pjax.git
To run the test suite locally, start up the Sinatra test application.
== Sinatra/1.3.2 has taken the stage on 4567 for development with backup from WEBrick