17

Im looking for a good way to setup paging for new items with a simple "load more" button at the bottom.

I know i'd use something like

{% if craft.request.isAjax %}

on the listing template to not include the main _layout file for the ajax requests and then using the paginate tags to control which entries to return.

Curious is anyone has a more streamlined approach

2
  • 1
    Hey Keith, glad you came up with a working solution. Can you please edit it out of your question area and post it as an actual answer? That way your solution shows up alongside other possible solutions, and can be voted on like them. Commented Jun 13, 2014 at 20:18
  • Sure makes sense Commented Jun 13, 2014 at 20:19

3 Answers 3

9

Hey So here is what i came up with, curious if anyone has a more streamlined approach.

https://gist.github.com/keithmancuso/17619fc405a621b4a11e

{% if craft.request.isAjax %}
    {% set layout = "_ajaxLayout" %}
{% else %}
    {% set layout = "_layout" %}
{% endif %}

{% extends layout %}

{% set limit = 10 %}
{% set params = { section: 'news', limit: limit} %}

{% block content %}

{% if not craft.request.isAjax %}
<h1>News</h1>
<div id="news-entries">
{% endif %}

{% paginate craft.entries(params) as entries %}
{% for entry in entries %}
  <article class="news">
    <h2><a href="{{ entry.url }}">{{ entry.title }}</a></h2>
    {{ entry.body }}
    </article>
{% endfor %}
{% endpaginate %}

{% if not craft.request.isAjax %}
</div>

<a href="#" id="loadMore" class="btn btn-default">load more news</a>

<div id="loading" style="display:none">
    <img src="/images/loading.gif"/>
</div>



{% set pagingJs %}

$(function () {

    var page = 2;

    $('#loadMore').click (function (e) {
        e.preventDefault();

        $('#loading').show();

        $.get( "/news/p"+page, function( data ) {

          $( "#news-entries" ).append( data );
          $('.loading').hide();
          page++;

        });

    });
});

{% endset %}

{% includeJs pagingJs %}

{% endif %}

{% endblock %}
6
  • One issue I'm still having is how do I know when I'm at the end of the pages? Commented Jun 13, 2014 at 22:15
  • I would think you'd have one of two options: 1. your JSON response starts returning empty results and #loadMore can be reactive, or 2. you could return the total number of entries along with counts in that JSON response, modifying your JavaScript to act accordingly when the last posts come through.
    – Matt Stein
    Commented Jun 18, 2014 at 15:02
  • the problem seems to be that even that /p100 still returns results, it seems to just start back at the begining. maybe thats a bug in the paging stuff? Commented Jun 18, 2014 at 16:59
  • I'm not sure, but I bet Brandon or Brad would be!
    – Matt Stein
    Commented Jun 18, 2014 at 17:21
  • I know this is a bit old but has anyone found a solution to determine the end of entries to hide the load more?
    – Bowenac
    Commented May 22, 2015 at 15:24
6

Thanks to Kieth for posting an ajax solution. I just wanted to expand on it a little bit to figure out when we are at the end of the entries etc so we can hide loading more buttons etc. Here is what I did.

In my example I am only loading 2 entries for each click so I'm setting the count to 2, and then incrementing the count on each click by 2.

Here I am getting the total count for the entries above and putting this in a hidden input field inside my main container for the ajax section. Don't mind the .id('and, not '~featuredArticleIdsString) as I am just getting featured entries above this and then getting those id's so I can exclude them from the ajax section as I don't want to duplicate those entries.

{% set category = craft.categories.group('resource') %}
{% set featuredArticleIds = craft.entries.relatedTo(category).limit(3).ids() %}
{% set featuredArticleIdsString = featuredArticleIds | join(', not ') %}
{% set totalEntries = craft.entries.relatedTo(category).id('and, not '~featuredArticleIdsString).find() %}
{% set totalCount = totalEntries | length %}
<!-- Ajax Container Start -->
<div class="container-fluid add-top resources">
    <!-- Set the total count of entries we will have access to in this section-->
    <input id="totalResourceCount" type="hidden" value="{{totalCount}}">

Then here is the ajax section...

{% set pagingJs %}
$(function () {
    var page = 2;
    // Since we are getting two entries per click we need to set count to 2 to start
    var count = 2
   // Get the total count that we set above
    var totalCount = $("#totalResourceCount").val();
    $('#loadMore').click (function (e) {
        e.preventDefault();
        // Check if count is less than totalCount
        if(count < totalCount){
            $('#loading').show();

            $.get( "/resource-ajax/p"+page, function( data ) {

                $( "#featuredResults" ).prepend( data ).fadeIn("slow");
                $('#loading').hide();
                page++;
                // Increment count by 2 entries
                count = (count) + 2;
                // Check if count is greater than or equal to the total count. If so hide the load more button. We need to check if count is greater than since we are incrementing an even number in case are total count is an odd. For example if we have total of 5 entries the second click would set the count to 6...
                if(count >= totalCount){
                    $("#loadMore").hide();
                }
            });
        }
    });
});
{% endset %}
{% includeJs pagingJs %}
4

I would use Craft's built in paginate tag. You just add the page number (p2, p3, p4, etc.) to the end of the url in your ajax call and output the template like this:

{% paginate craft.entries.section('blog').limit(10) as entries %}
    {% for entry in entries %}
        <h1>{{ entry.title }}</h1>
        {{ entry.body }}
    {% endfor %}
{% endpaginate %}
1
  • You can also edit p2, p3 etc to a different format if you wish by adding something like 'pageTrigger'=> 'page-' inside the array found in craft/config/general.php
    – H2ONOCK
    Commented Oct 24, 2015 at 11:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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