pushState + ajax = pjax

pushState + ajax = pjax

   /    \
  ## a  a
  (   '._)
   |'-- |
 _.\___/_   ___pjax___

.”> \Y/|<‘. ‘._.-’ / \ _\/ / ‘-’ / | –’_/|/ | _/ |_.-’ | |' | | | | / ‘./ /./| | \ | | \ | | ; | | / | | jgs |___\_.\_ -“–’—’

what is it?

pjax loads HTML from your server into the current page without a full reload. It’s ajax with real permalinks, page titles, and a working back button that fully degrades.

pjax enhances the browsing experience - nothing more.

You can find a demo at http://pjax.heroku.com/

three ways to pjax on the client side:

  1. Functionally obtrusive, loading the href with ajax into data-pjax:



  1. Slightly obtrusive, passing a container and jQuery ajax options:


$(‘a.js-pjax’).pjax(‘#main’, { timeout: null, error: function(xhr, err){ $(‘.error’).text(‘Something went wrong: ’ + err) })

  1. Unobtrusive, showing a ‘loading’ spinner:

$(‘a’).pjax(‘#main’).live(‘click’, function(){ $(this).showLoader() })

$(link).pjax( container, options )

The $(link).pjax() function accepts a container, an options object, or both. The options are the same as jQuery’s $.ajax options with the following additions:

    container - The selector of the container to load the reponse body into, or
                the container itself.

clickedElement - The element that was clicked to start the pjax call. push - Whether to pushState the URL. Defaults to true (of course). replace - Whether to replaceState the URL. Defaults to false. timeout - pjax sets this low, <1s. Set this higher if using a custom error handler. It’s in ms, so something like timeout: 2000 error - By default this callback reloads the target page once timeout ms elapses.

$.pjax( options )

You can also just call $.pjax directly. It acts much like $.ajax, even returning the same thing and accepting the same options.

The pjax-specific keys listed in the $(link).pjax() section work here as well.

This pjax call:

$.pjax({ url: ‘/authors’, container: ‘#main’ })

Roughly translates into this ajax call:

$.ajax({ url: ‘/authors’, dataType: ‘html’, beforeSend: function(xhr){ xhr.setRequestHeader(‘X-PJAX’, ‘true’) }, success: function(data){ $(‘#main’).html(data) history.pushState(null, $(data).filter(‘title’).text(), ‘/authors’) }) })

pjax on the server side

You’ll want to give pjax requests a ‘chrome-less’ version of your page. That is, the page without any layout.

As you can see in the “ajax call” example above, pjax sets a custom ‘X-PJAX’ header to ‘true’ when it makes an ajax request to make detecting it easy.

In Rails, check for request.headers['X-PJAX']:

def my_page if request.headers[‘X-PJAX’] render :layout => false end end

Django: https://github.com/jacobian/django-pjax

Asp.Net MVC3: http://biasecurities.com/blog/2011/using-pjax-with-asp-net-mvc3/

page titles

Your HTML should also include a tag if you want page titles to work.</p> <h2>events</h2> <p>pjax will fire two events on the container you’ve asked it to load your reponse body into:</p> <ul> <li>start.pjax - Fired when a pjax ajax request begins.</li> <li>end.pjax - Fired when a pjax ajax request ends.</li> </ul> <p>This allows you to, say, display a loading indicator upon pjaxing:</p> <p>$(‘a.pjax’).pjax(‘#main’) $(‘#main’) .bind(‘start.pjax’, function() { $(‘#loading’).show() }) .bind(‘end.pjax’, function() { $(‘#loading’).hide() })</p> <h2>browser support</h2> <p>pjax only works with browsers that support the history.pushState API.</p> <p>For a table of supported browsers see: <a href="http://caniuse.com/#search=pushstate">http://caniuse.com/#search=pushstate</a></p> <h2>install it</h2> <p>$ cd path/to/js $ curl -O <a href="https://github.com/defunkt/jquery-pjax/raw/master/jquery.pjax.js">https://github.com/defunkt/jquery-pjax/raw/master/jquery.pjax.js</a></p> <p>Then, in your HTML:</p> <p><script src="path/to/js/jquery.pjax.js"></script></p> <p>Replace ‘path/to/js’ with the path to your JavaScript directory, e.g. ‘public/javascripts’.</p> </article> <div class="col-md-4" style="margin-bottom: 50px"> <h3>Related Repositories</h3> <div class="row" style="margin-bottom: 10px"> <div class="col-md-4"> <a href="/repos/defunkt-jquery-pjax"><img src="https://avatars3.githubusercontent.com/u/2?v=3" alt="jquery-pjax" title="jquery-pjax" class="lazyload" width="100"></a> </div> <div class="col-md-8"> <h4><a href="/repos/defunkt-jquery-pjax">jquery-pjax</a></h4> <p>pushState + ajax = pjax ...</p> </div> </div> <div class="row" style="margin-bottom: 10px"> <div class="col-md-4"> <a href="/repos/ckald-jquery-pjax"><img src="https://avatars.githubusercontent.com/u/204759?v=3" alt="jquery-pjax" title="jquery-pjax" class="lazyload" width="100"></a> </div> <div class="col-md-8"> <h4><a href="/repos/ckald-jquery-pjax">jquery-pjax</a></h4> <p>jQuery PJAX with old-school hashes support ...</p> </div> </div> <div class="row" style="margin-bottom: 10px"> <div class="col-md-4"> <a href="/repos/yiisoft-jquery-pjax"><img src="https://avatars.githubusercontent.com/u/993323?v=3" alt="jquery-pjax" title="jquery-pjax" class="lazyload" width="100"></a> </div> <div class="col-md-8"> <h4><a href="/repos/yiisoft-jquery-pjax">jquery-pjax</a></h4> <p>pushState + ajax = pjax ...</p> </div> </div> <div class="row" style="margin-bottom: 10px"> <div class="col-md-4"> <a href="/repos/eddyystop-jquery-pjax-toolkit"><img src="https://avatars.githubusercontent.com/u/1553311?v=3" alt="jquery-pjax-toolkit" title="jquery-pjax-toolkit" class="lazyload" width="100"></a> </div> <div class="col-md-8"> <h4><a href="/repos/eddyystop-jquery-pjax-toolkit">jquery-pjax-toolkit</a></h4> <p>A toolkit for jquery-pjax. Useful utilities & a micro framework. ...</p> </div> </div> <div class="row" style="margin-bottom: 10px"> <div class="col-md-4"> <a href="/repos/clipperhouse-jquery-pjax"><img src="https://avatars.githubusercontent.com/u/216057?v=3" alt="jquery-pjax" title="jquery-pjax" class="lazyload" width="100"></a> </div> <div class="col-md-8"> <h4><a href="/repos/clipperhouse-jquery-pjax">jquery-pjax</a></h4> <p>pushState + ajax = pjax ...</p> </div> </div> <br> <h3>Top Contributors</h3> <div> <a href="/developer/defunkt" target="_blank" rel="nofollow"> <img src="https://avatars.githubusercontent.com/u/2?v=3" alt="defunkt" title="defunkt" class="pull-left" width="60" height="60" style="width:60px;height:60px;" /> </a> <a href="/developer/brianmario" target="_blank" rel="nofollow"> <img src="https://avatars.githubusercontent.com/u/11571?v=3" alt="brianmario" title="brianmario" class="pull-left" width="60" height="60" style="width:60px;height:60px;" /> </a> <a href="/developer/littke" target="_blank" rel="nofollow"> <img src="https://avatars.githubusercontent.com/u/227383?v=3" alt="littke" title="littke" class="pull-left" width="60" height="60" style="width:60px;height:60px;" /> </a> <a href="/developer/mislav" target="_blank" rel="nofollow"> <img src="https://avatars.githubusercontent.com/u/887?v=3" alt="mislav" title="mislav" class="pull-left" width="60" height="60" style="width:60px;height:60px;" /> </a> <a href="/developer/morten" target="_blank" rel="nofollow"> <img src="https://avatars.githubusercontent.com/u/14324?v=3" alt="morten" title="morten" class="pull-left" width="60" height="60" style="width:60px;height:60px;" /> </a> <a href="/developer/mono0x" target="_blank" rel="nofollow"> <img src="https://avatars.githubusercontent.com/u/231380?v=3" alt="mono0x" title="mono0x" class="pull-left" width="60" height="60" style="width:60px;height:60px;" /> </a> </div> <div style="clear: both"></div> <br> </div> </div> </div> <div aria-hidden="true" aria-labelledby="reviewModalLabel" role="dialog" tabindex="-1" id="reviewModal" class="modal fade in"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button data-dismiss="modal" class="close" type="button"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> <h4 id="mcqReviewModalLabel" class="modal-title">Would you tell us more about spantaleev/jquery-pjax?</h4> </div> <form style="padding:10px;" action="/review" method="POST" role="form" id="review-form" class="form-horizontal bv-form" novalidate="novalidate"> <input type="hidden" value="416132" name="repos_id"> <div style="padding-top:0;" class="modal-body"> <div class="form-group mcq_input"> <h4>Is the project reliable?</h4> <div class="input-group"> <div class="radio"> <label><input type="radio" value="1" name="reliable">Yes, realiable</label>    <label><input type="radio" value="0" name="reliable">Somewhat realiable</label>    <label><input type="radio" value="-1" name="reliable">Not realiable</label> </div> </div> </div> <div class="form-group mcq_input has-feedback"> <h4>Would you recommend this project?</h4> <div class="input-group"> <div class="radio"> <label><input type="radio" class="definitely_recommend" value="1" name="recommendation">Yes, definitely</label>    <label><input type="radio" class="no_recommend" value="0" name="recommendation">Not sure</label>    <label><input type="radio" class="no_recommend" value="-1" name="recommendation">Nope</label> </div> </div> </div> <div class="form-group mcq_input"> <h4>Is the documentation helpful?</h4> <div class="input-group"> <div class="radio"> <label><input type="radio" value="1" name="documentation">Yes, helpful</label>    <label><input type="radio" value="0" name="documentation">Somewhat helpful</label>    <label><input type="radio" value="-1" name="documentation">Not that helpful</label> </div> </div> </div> <div class="modal-footer"> <button data-dismiss="modal" class="btn btn-default" type="button">Close</button> <button class="btn btn-primary" type="submit" name="button">Submit</button> </div> </div> </form> </div> </div> </div> </section> <footer id="footer"> <div class="container footer-container"> <div class="row"> <div class="col-md-3"> <a href="/" style="color: #26272d; font-weight: 700; text-transform: uppercase;font-size: 12px;">DevHub.io</a> <p>Recommended high-quality free and open source development tools, resources, reading. <br> Currently tracking <a href="list/newest">1463788</a> open source projects, <a href="developers">465813</a> developers</p> <ul class="socials"> <li><a href="https://twitter.com/HubDevelop" target="_blank"><i class="fa fa-twitter"></i></a></li> <li><a href="https://www.facebook.com/devhubdotio" target="_blank"><i class="fa fa-facebook"></i></a></li> <li><a href="mailto:devhub.io@gmail.com"><i class="fa fa-envelope-o"></i></a></li> </ul> </div> <div class="col-md-2 col-md-offset-4 col-sm-4 col-xs-6 footer-links"> <ul> <li><p class="title">Website</p></li> <li><a href="#">About</a></li> <li><a href="#">Contact Us</a></li> <li><a href="//status.devhub.io/">Status</a></li> <li><a href="#">API</a></li> <li><a href="https://github.com/devhub-io">Github</a></li> </ul> </div> <div class="col-md-2 col-sm-4 col-xs-6 footer-links"> <ul> <li><p class="title">GATEGORY</p></li> <li><a href="/category/lang">Languages</a></li> <li><a href="/category/frontend">Frontend</a></li> <li><a href="/category/server">Server</a></li> <li><a href="/category/app">App</a></li> <li><a href="/category/design">Design</a></li> <li><a href="/category/read">Read</a></li> </ul> </div> </div> </div> <div class="container copyright-container"> <div class="row"> <div class="col-md-8 text-left"> <div class="more-info"> <p class="copyright-title">© 2016 - 2020 DevHub.io. All Rights Reserved.</p> <p class="copyright-tips">Disclaimer: This project is not affiliated with the GitHub company in any way. GitHub® and the Octocat® logo are registered trademarks of GitHub, Inc., used with permission—https://github.com/logos</p> </div> </div> <div class="col-md-4"> <div class="row"> <div class="col-md-6 text-right"> <div class="made-by">Power by</div> </div> <div class="col-md-6"> <svg xmlns="http://www.w3.org/2000/svg" width="91" height="18"> <linearGradient id="smooth" x2="0" y2="100%"> <stop offset="0" stop-color="#fff" stop-opacity=".7"></stop> <stop offset=".1" stop-color="#aaa" stop-opacity=".1"></stop> <stop offset=".9" stop-color="#000" stop-opacity=".3"></stop> <stop offset="1" stop-color="#000" stop-opacity=".5"></stop> </linearGradient> <rect rx="4" width="91" height="18" fill="#555555"></rect> <rect rx="4" x="48" width="43" height="18" fill="#4c1"></rect> <rect x="48" width="4" height="18" fill="#4c1"></rect> <rect rx="4" width="91" height="18" fill="url(#smooth)"></rect> <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> <text x="25" y="13" fill="#010101" fill-opacity=".3">Server</text> <text x="25" y="12">Server</text> <text x="68.5" y="13" fill="#010101" fill-opacity=".3">Nginx</text> <text x="68.5" y="12">Nginx</text> </g> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="106" height="18"> <linearGradient id="smooth" x2="0" y2="100%"> <stop offset="0" stop-color="#fff" stop-opacity=".7"></stop> <stop offset=".1" stop-color="#aaa" stop-opacity=".1"></stop> <stop offset=".9" stop-color="#000" stop-opacity=".3"></stop> <stop offset="1" stop-color="#000" stop-opacity=".5"></stop> </linearGradient> <rect rx="4" width="106" height="18" fill="#555555"></rect> <rect rx="4" x="36" width="70" height="18" fill="#1abc9c"></rect> <rect x="36" width="4" height="18" fill="#1abc9c"></rect> <rect rx="4" width="106" height="18" fill="url(#smooth)"></rect> <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> <text x="19" y="13" fill="#010101" fill-opacity=".3">CDN</text> <text x="19" y="12">CDN</text> <text x="70" y="13" fill="#010101" fill-opacity=".3">CloudFlare</text> <text x="70" y="12">CloudFlare</text> </g> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="124" height="18"> <linearGradient id="smooth" x2="0" y2="100%"> <stop offset="0" stop-color="#fff" stop-opacity=".7"></stop> <stop offset=".1" stop-color="#aaa" stop-opacity=".1"></stop> <stop offset=".9" stop-color="#000" stop-opacity=".3"></stop> <stop offset="1" stop-color="#000" stop-opacity=".5"></stop> </linearGradient> <rect rx="4" width="124" height="18" fill="#555555"></rect> <rect rx="4" x="72" width="52" height="18" fill="#007ec6"></rect> <rect x="72" width="4" height="18" fill="#007ec6"></rect> <rect rx="4" width="124" height="18" fill="url(#smooth)"></rect> <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> <text x="37" y="13" fill="#010101" fill-opacity=".3">Framework</text> <text x="37" y="12">Framework</text> <text x="97" y="13" fill="#010101" fill-opacity=".3">Golang</text> <text x="97" y="12">Golang</text> </g> </svg> </div> </div> </div> </div> </div> </footer> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/peity/3.2.0/jquery.peity.min.js"></script> <script type="text/javascript" src="/statics/js/jquery.sticky.js"></script> <script type="text/javascript" src="/statics/js/wow.min.js"></script> <script type="text/javascript" src="/statics/js/owl.carousel.min.js"></script> <script type="text/javascript" src="/statics/js/app.js"></script> <script async defer src="https://buttons.github.io/buttons.js"></script> <script> $('#review-form').submit(function () { if ($('#review-form input[name=reliable]:checked').val() === undefined) { return false; } if ($('#review-form input[name=recommendation]:checked').val() === undefined) { return false; } if ($('#review-form input[name=documentation]:checked').val() === undefined) { return false; } return true; }); </script> <script> console.info( ' _____ _ _ _ \n' + ' | __ \\ | | | | | | \n' + ' | | | | _____ _| |__| |_ _| |__ \n' + ' | | | |/ _ \\ \\ / / __ | | | | \'_ \\ \n' + ' | |__| | __/\\ V /| | | | |_| | |_) | \n' + ' |_____/ \\___| \\_/ |_| |_|\\__,_|_.__/ \n' + ' --------------------------------------\n' + ' https://devhub.io '); $("span.line").peity("line"); </script> <script> window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date; ga('create', 'UA-35989028-4', 'auto'); ga('require', 'GTM-T37PMGT'); ga('send', 'pageview'); </script> <script async src='https://www.google-analytics.com/analytics.js'></script> <script> if (typeof ga !== "undefined" && ga !== null) { $(document).ajaxSend(function (event, xhr, settings) { ga('send', 'pageview', settings.url); }); (function (window) { var undefined, link = function (href) { var a = window.document.createElement('a'); a.href = href; return a; }; window.onerror = function (message, file, line, column) { var host = link(file).hostname; ga('send', { 'hitType': 'event', 'eventCategory': (host == window.location.hostname || host == undefined || host == '' ? '' : 'external ') + 'error', 'eventAction': message, 'eventLabel': (file + ' LINE: ' + line + (column ? ' COLUMN: ' + column : '')).trim(), 'nonInteraction': 1 }); }; }(window)); $(function () { var isDuplicateScrollEvent, scrollTimeStart = new Date, $window = $(window), $document = $(document), scrollPercent; $window.scroll(function () { scrollPercent = Math.round(100 * ($window.height() + $window.scrollTop()) / $document.height()); if (scrollPercent > 90 && !isDuplicateScrollEvent) { //page scrolled to 90% isDuplicateScrollEvent = 1; ga('send', 'event', 'scroll', 'Window: ' + $window.height() + 'px; Document: ' + $document.height() + 'px; Time: ' + Math.round((new Date - scrollTimeStart ) / 1000, 1) + 's' ); } }); }); if (window.performance) { var timeSincePageLoad = Math.round(performance.now()); ga('send', 'timing', 'JS Dependencies', 'load', timeSincePageLoad); } } </script> <script type="text/javascript"> window.doorbellOptions = { appKey: 'akmfqdy1fBgL1corAEydarDdZdwk4P55B94bk8vMbIvnXUTD7mxxYsXKrHeY96fG' }; (function(w, d, t) { var hasLoaded = false; function l() { if (hasLoaded) { return; } hasLoaded = true; window.doorbellOptions.windowLoaded = true; var g = d.createElement(t);g.id = 'doorbellScript';g.type = 'text/javascript';g.async = true;g.src = 'https://embed.doorbell.io/button/5155?t='+(new Date().getTime());(d.getElementsByTagName('head')[0]||d.getElementsByTagName('body')[0]).appendChild(g); } if (w.attachEvent) { w.attachEvent('onload', l); } else if (w.addEventListener) { w.addEventListener('load', l, false); } else { l(); } if (d.readyState == 'complete') { l(); } }(window, document, 'script')); </script> </body> </html>