How do i setup ajax paging for entries

16

6

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

Keith Mancuso

Posted 2014-06-13T17:32:48.643

Reputation: 1 544

1Hey 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. – Brandon Kelly – 2014-06-13T20:18:47.047

Sure makes sense – Keith Mancuso – 2014-06-13T20:19:28.477

Answers

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 %}

Keith Mancuso

Posted 2014-06-13T17:32:48.643

Reputation: 1 544

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 – 2015-05-22T15:24:41.347

Update: figured out a solution will post as an answer including code from Keith Mancuso. – Bowenac – 2015-05-22T15:50:29.040

One issue I'm still having is how do I know when I'm at the end of the pages? – Keith Mancuso – 2014-06-13T22:15:11.337

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 – 2014-06-18T15:02:55.100

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? – Keith Mancuso – 2014-06-18T16:59:15.487

I'm not sure, but I bet Brandon or Brad would be! – Matt Stein – 2014-06-18T17:21:46.603

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 %}

Bowenac

Posted 2014-06-13T17:32:48.643

Reputation: 469

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 %}

Bryan Redeagle

Posted 2014-06-13T17:32:48.643

Reputation: 3 867

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 – 2015-10-24T11:07:09.460