I haven't used AJAX a lot, but what I want to do is the following:

I have a top navigation that outputs entries from a structure which link to various singles that display my data. I want my navigation to stay and not reload when going to another page. How would I implement AJAX combined with Craft for that?


I'm not sure this is a really a Craft-specific question, but here's a basic strategy:

  1. Build your nav and pages to work without any Ajax calls. Make sure your nav is output consistently (e.g. in <nav class="primary-nav") as well as the content of the page (e.g. in <div class="main">).

  2. Now implement your JavaScript. You want to (a) intercept navigation link clicks to stop a full page reload, (b) Ajax in the new content, (c) move the active class to the clicked navigation link, and (d) change the URL to the new page address. Make sure to use History.js to smooth out any difference in browser implementation of HTML5's history API (including pushState).

Here's a demo (and code) I cooked up with static HTML. It's based on Andrew Fricke's post titled Rolling your own PJAX Implementation with History.js

  • Thanks James, History.js is great but I never got it working properly. This definitely helps a lot!
    – carlcs
    Nov 18 '14 at 23:03

In addition to James Muspratt's excellent answer, I thought I might share some other tips that I have learned. In your page templates you can use conditionals to modify the behavior based on whether its an ajax request or not. In this way you can design your templates to work both as Ajax requests and as direct requests, which is great for SEO and other uses.

One problem for example with ajax loaded templates is that live preview may not work in the CP if the template is not also designed to load in the header, css, js, nav, etc. One way around this is to extend a different template based on the type of request:

{% extends craft.request.isAjax and not craft.request.isLivePreview ? "_ajax" : "_layout" %}

As you can see, if it's ajax I'm extending a template that has nothing but a content block defined; and it's not ajax then I'll extend the full template with head, js, css, nav, etc. The catch is that Live Preview also uses ajax, so we want the full template anyway.

You can also use the same method to return slightly modified content. In this case, I'm just loading the raw _product template for ajax requests and wrapping it as needed for non-ajax:

{% block content %}

{% if craft.request.isAjax and not craft.request.isLivePreview %}

    {# return the raw _product template #}
    {% include 'products/_product.html' %}

{% else %}

    {# return the modified _product template wrapped properly for the full page layout #}
    <section id="products" class="products js-products">
        <div class="content">

            {% include 'products/_product.html' %}


{% endif %}

{% endblock %}

Hope this helps a bit, and doesn't make things more confusing.

  • Nice, I keep forgetting Craft can do that. And it means your JS doesn't have to do the work of parsing the HTML and extracting just the content block. Nov 19 '14 at 15:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.