JavaScript reference

For each type of pagination it is possible to enable Ajax so that the requested page is loaded using an asynchronous request to the server. This is especially important for Twitter-style Pagination and endless pagination on scroll, but Digg-style pagination can also take advantage of this technique.

Activating Ajax support

Ajax support is activated linking jQuery and the el-pagination.js file included in this app. It is then possible to use the $.endlessPaginate() jQuery plugin to enable Ajax pagination, e.g.:

<h2>Entries:</h2>
<div class="endless_page_template">
    {% include page_template %}
</div>

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>$.endlessPaginate();</script>
{% endblock %}

This example assumes that you separated the fragment containing the single page (page_tempate) from the main template (the code snipper above). More on this in Twitter-style Pagination and Digg-style pagination.

The $.endlessPaginate() call activates Ajax for each pagination present in the page.

Pagination on scroll

If you want new items to load when the user scrolls down the browser page, you can use the pagination on scroll feature: just set the paginateOnScroll option of $.endlessPaginate() to true, e.g.:

<h2>Entries:</h2>
<div class="endless_page_template">
    {% include page_template %}
</div>

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>$.endlessPaginate({paginateOnScroll: true});</script>
{% endblock %}

That’s all. See the Templatetags reference page to improve usage of the included templatetags.

It is possible to set the bottom margin used for pagination on scroll (default is 1 pixel). For example, if you want the pagination on scroll to be activated when 20 pixels remain to the end of the page:

<h2>Entries:</h2>
<div class="endless_page_template">
    {% include page_template %}
</div>

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>
        $.endlessPaginate({
            paginateOnScroll: true,
            paginateOnScrollMargin: 200
        });
    </script>
{% endblock %}

Attaching callbacks

It is possible to customize the behavior of JavaScript pagination by attaching callbacks to $.endlessPaginate(), called when the following events are fired:

  • onClick: the user clicks on a page link;
  • onCompleted: the new page is fully loaded and inserted in the DOM.

The context of both callbacks is the clicked link fragment: in other words, inside the callbacks, this will be the HTML fragment representing the clicked link, e.g.:

<h2>Entries:</h2>
<div class="endless_page_template">
    {% include page_template %}
</div>

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>
        $.endlessPaginate({
            onClick: function() {
                console.log('Label:', $(this).text());
            }
        });
    </script>
{% endblock %}

Both callbacks also receive a context argument containing information about the requested page:

  • context.url: the requested URL;
  • context.key: the querystring key used to retrieve the requested contents.

If the onClick callback returns false, the pagination process is stopped, the Ajax request is not performed and the onCompleted callback never called.

The onCompleted callbacks also receives a second argument: the data returned by the server. Basically this is the HTML fragment representing the new requested page.

To wrap it up, here is an example showing the callbacks’ signatures:

<h2>Entries:</h2>
<div class="endless_page_template">
    {% include page_template %}
</div>

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>
        $.endlessPaginate({
            onClick: function(context) {
                console.log('Label:', $(this).text());
                console.log('URL:', context.url);
                console.log('Querystring key:', context.key);
                if (forbidden) {  // to be defined...
                    return false;
                }
            },
            onCompleted: function(context, fragment) {
                console.log('Label:', $(this).text());
                console.log('URL:', context.url);
                console.log('Querystring key:', context.key);
                console.log('Fragment:', fragment);
            }
        });
    </script>
{% endblock %}

Manually selecting what to bind

As seen above, $.endlessPaginate() enables Ajax support for each pagination in the page. But assuming you are using Multiple paginations in the same page, e.g.:

<h2>Entries:</h2>
<div id="entries" class="endless_page_template">
    {% include "myapp/entries_page.html" %}
</div>

<h2>Other entries:</h2>
<div id="other-entries" class="endless_page_template">
    {% include "myapp/other_entries_page.html" %}
</div>

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>$.endlessPaginate();</script>
{% endblock %}

What if you need Ajax pagination only for entries and not for other entries? You can do this in a straightforward way using jQuery selectors, e.g.:

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>$('#entries').endlessPaginate();</script>
{% endblock %}

The call to $(‘#entries’).endlessPaginate() applies Ajax pagination starting from the DOM node with id entries and to all sub-nodes. This means that other entries are left intact. Of course you can use any selector supported by jQuery.

At this point, you might have already guessed that $.endlessPaginate() is just an alias for $(‘body’).endlessPaginate().

Customize each pagination

You can also call $.endlessPaginate() multiple times if you want to customize the behavior of each pagination. E.g. if you need to register a callback for entries but not for other entries:

<h2>Entries:</h2>
<div id="entries" class="endless_page_template">
    {% include "myapp/entries_page.html" %}
</div>

<h2>Other entries:</h2>
<div id="other-entries" class="endless_page_template">
    {% include "myapp/other_entries_page.html" %}
</div>

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>
        $('#entries').endlessPaginate({
            onCompleted: function(data) {
                console.log('New entries loaded.');
            }
        });
        $('#other-entries').endlessPaginate();
    </script>
{% endblock %}

Selectors

Each time $.endlessPaginate() is used, several JavaScript selectors are used to select DOM nodes. Here is a list of them all:

  • containerSelector: ‘.endless_container’ (Twitter-style pagination container selector);
  • loadingSelector: ‘.endless_loading’ - (Twitter-style pagination loading selector);
  • moreSelector: ‘a.endless_more’ - (Twitter-style pagination link selector);
  • contentSelector: null - (Twitter-style pagination content wrapper);
  • pageSelector: ‘.endless_page_template’ (Digg-style pagination page template selector);
  • pagesSelector: ‘a.endless_page_link’ (Digg-style pagination link selector).

An example can better explain the meaning of the selectors above. Assume you have a Digg-style pagination like the following:

<h2>Entries:</h2>
<div id="entries" class="endless_page_template">
    {% include "myapp/entries_page.html" %}
</div>

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>
        $('#entries').endlessPaginate();
    </script>
{% endblock %}

Here the #entries node is selected and Digg-style pagination is applied. Digg-style needs to know which DOM node will be updated with new contents, and in this case it’s the same node we selected, because we added the endless_page_template class to that node, and .endless_page_template is the selector used by default. However, the following example is equivalent and does not involve adding another class to the container:

<h2>Entries:</h2>
<div id="entries">
    {% include "myapp/entries_page.html" %}
</div>

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>
        $('#entries').endlessPaginate({
            pageSelector: '#entries'
        });
    </script>
{% endblock %}

On scroll pagination using chunks

Sometimes, when using on scroll pagination, you may want to still display the show more link after each N pages. In Django Endless Pagination this is called chunk size. For instance, a chunk size of 5 means that a show more link is displayed after page 5 is loaded, then after page 10, then after page 15 and so on. Activating this functionality is straightforward, just use the paginateOnScrollChunkSize option:

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>
        $.endlessPaginate({
            paginateOnScroll: true,
            paginateOnScrollChunkSize: 5
        });
    </script>
{% endblock %}

Each time a chunk size is complete, the class endless_chunk_complete is added to the show more link, so you still have a way to distinguish between the implicit click done by the scroll event and a real click on the button.

Migrate from version 1.1 to 2.1

Django Endless Pagination v2.0 introduces changes in how Ajax pagination is handled by JavaScript. These changes are discussed in this document and in the Changelog.

The JavaScript code now lives in a file named el-pagination.js. The two JavaScript files el-pagination-endless.js and el-pagination_on_scroll.js was removed. However, please consider migrating: the old JavaScript files was removed, are no longer maintained, and don’t provide the new JavaScript features.

Instructions on how to migrate from the old version to the new one follow.

Basic migration

Before:

<h2>Entries:</h2>
{% include page_template %}

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination-endless.js"></script>
{% endblock %}

Now:

<h2>Entries:</h2>
{% include page_template %}

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>$.endlessPaginate();</script>
{% endblock %}

Pagination on scroll

Before:

<h2>Entries:</h2>
{% include page_template %}

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination-endless.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination_on_scroll.js"></script>
{% endblock %}

Now:

<h2>Entries:</h2>
{% include page_template %}

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>
        $.endlessPaginate({paginateOnScroll: true});
    </script>
{% endblock %}

Pagination on scroll with customized bottom margin

Before:

<h2>Entries:</h2>
{% include page_template %}

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination-endless.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination_on_scroll.js"></script>
    <script>
        var endless_on_scroll_margin = 200;
    </script>
{% endblock %}

Now:

<h2>Entries:</h2>
{% include page_template %}

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>
        $.endlessPaginate({
            paginateOnScroll: true,
            paginateOnScrollMargin: 200
        });
    </script>
{% endblock %}

Avoid enabling Ajax on one or more paginations

Before:

<h2>Other entries:</h2>
<div class="endless_page_template endless_page_skip">
    {% include "myapp/other_entries_page.html" %}
</div>

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination-endless.js"></script>
{% endblock %}

Now:

<h2>Other entries:</h2>
<div class="endless_page_template endless_page_skip">
    {% include "myapp/other_entries_page.html" %}
</div>

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>$('not:(.endless_page_skip)').endlessPaginate();</script>
{% endblock %}

In this last example, activating Ajax just where you want might be preferred over excluding nodes.