Pagination


Basics

All zajFetcher objects (which is the default type of any zajModel::fetch() list) have pagination features built right in which make it much easier to work with multi-page lists.

Here’s how to make a list where users are paginated by 15 per page:

$this->zajlib->variable->users = User::fetch()->paginate(15);

When you list the items with {% foreach %} it will just list the first 15 items:

{% foreach users as user %}
  {{forloop.counter|add:users.pagination.pagefirstitem0}}. {{user.name}}
{% endforeach %}

Finally, you need to add some pagination links. These will automatically have the proper query string data appended so that pagination should usually work by default, no matter what query string data you already have present on the page:

{{users.pagination.prev}} | {{users.pagination.next}}

If you have Bootstrap enabled, you can also use the pre-built pagination template filter:

{{users|pagination:'people'}}

This will output something like this:

Pagination variables

Once you’ve paginated a list of model objects (User::fetch()->paginate(15); or {{users|paginate:15}}) you can use the pagination object which contains a number of helpful variables. These can be used in the following way:

{% foreach users as user %}
  {{forloop.counter|add:users.pagination.pagefirstitem0}}. {{user.name}}
{% endforeach %}
{{users.pagination.prev}} | {{users.total}} people on {{users.pagination.pagecount}} pages | {{users.pagination.next}}

Here are all the available variables:

  • page – int – the current page number
  • perpage – int – the number per page
  • pagecount – int – the number of pages
  • pagefirstitem0 – int – the count of the first item on this page, 0-indexed
  • pagefirstitem – int – the count of the first item on this page
  • nextpage – int – the next page number
  • prevpage – int – the previous page number
  • nexturl – string – the url of the next page
  • prevurl – string – the url of the previous page
  • pageurl – string – the url without a page number
  • next – html – an html link to the next page with an arrow
  • prev – html – an html link to the previous page with an arrow
  • autopagination – json string – json-encoded data about the pagination which is used during infinite scroll.

Pagination filters

There are two filters which are related to pagination:

{{list|paginate:15}} – paginates the items in list by the number given (15 in this case)
{{list|pagination:'items'}} – displays a Bootstrap-enabled pagination widget with ‘items’ used as the text (see above)

Manual pagination

You don’t have to use the built-in pagination features. For example, if you want to change the way the URL parameters look when you paginate, you’ll have to manage pagination manually. This too is fairly simple…much like with the automatic features, you’ll need to use the paginate() method.

The paginate() method actually takes two parameters:

{integer} $perpage The number of items to list per page.
{integer|bool} $page The current page number. This is normally controlled automatically via the created template variables.

Instead of just specifying the first parameter, you can also set the second:

if(empty($_GET['page']) || !is_numeric($_GET['page'])) $_GET['page'] = 1;
$this->zajlib->variable->list->paginate(15, $_GET['page']);

As above, the pagination variables will be available in the template, so you can generate any pagination code you need:

<a href='{{baseurl}}list/?page={{list.pagination.prevpage}}'>Previous page</a> <a href='{{baseurl}}list/?page={{list.pagination.nextpage}}'>Next page</a>

Infinite scroll

You can also automatically paginate on scroll. This will work similar to your Facebook feed – when you scroll to the bottom it will automatically load more items. To do this, follow these steps:

  1. create a block called autopagination around the paginated list
  2. add a data-autopagination attribute to the parent element

Here’s a quick example:

<div data-autopagination="{{users.pagination.autopagination}}">
  {% block autopagination %}
    {% foreach users as user %}
      {{forloop.counter|add:users.pagination.pagefirstitem0}}. {{user.name}}
    {% endforeach %}
  {% endblock %}
</div>

When loading, the autopagination script creates a new div element. This element will have a class ofw-watchelement. While loading a new page, the element will have visibility: visible but in other cases it will be visibility: hidden.

<!-- Automatically added to list div -->
<div class="ofw-watchelement ModelName"></div>

Tip! For optimal usability, you should not include any clickable content BELOW the ofw-watchelement div. Each time the user scrolls to it, it will move further down, thus making any such content very difficult and annoying to try to click on.

Warning! You need to style this element so that it shows up at the BOTTOM of your list of child elements. If this does not happen, you may get unexpected results with autopagination. It is possible that you may need to add styles such as setting its position, its float value, etc. Make sure it works right across various browsers.

You can also add styling to the .ofw-watchelement element so that it displays a loader gif:

.ofw-watchelement{
  background-image: url(//example.com/system/img/assets/ajax-loader.gif);
  display: block;
  height: 11px;
  background-repeat: no-repeat;
  background-position: 50% 50%;
  float: left;
}

Inifinite scroll options

You can use data-attributes to customize how infinite scroll will work. Here are a list of available options:

  • data-autopagination-block – set the name of the block you will use for this paginator. this can be useful when you have multiple infinite scrolls on a single page.
  • data-autopagination-button – use this to define a ‘Click here for more’ button if you prefer using a button instead of automatic pagination on scroll. See below for more info on this.
  • data-autopagination-data – you can use this attribute to send additional data along with the autopagination GET request. It will be attached to the request and accessible in PHP via the standard $_GET[‘autopagination_data’]. This is useful when you have complex layouts or multiple infinite scrolls on a single page.

Example of using options:

Callback after infinite scroll pagination

Many times you’ll need to execute functions or inspect the DOM after the autopagination successfully loads. You can register one or more autopagination callback functions by using the zaj.autopagination.ready() method.

function enable_something(modelName, currentPageNumber){
  // Some important code goes here
}
zaj.autopagination.ready(enable_something);

Warning! Unlike zaj.ready() or $(document).ready() you need to be aware that autopagination callback functions may be executed several times (once for every time another page is loaded). Be sure to take this into account when writing your code. You can use the modelName and currentPageNumber parameters to add additional logic.

Infinite scroll with Masonry

  • a masonry brickek containere legyen relative
  • a masonry brick elemnek ne legyen position és float css stílusa, és legfeljebb alsó margója legyen.
  • az infinite scroll callback függvényére tegyél egy callbacket:
    zaj.autopagination.ready(function(){refreshMasonry(true)});
  • a refreshMasonry() függvényben ezeket add meg: a width az masonry oszlopod szélessége, a gutter lényegében a css margin-left-nek felel meg:
    function refreshMasonry(destroyMe){
      var $container = $('#masonrycontainer');
      if(destroyMe) $container.masonry('destroy');// initialize
        $container.masonry({
          columnWidth: 165,
          itemSelector: '.brick',
          gutter: 20
       });
      }
      zaj.ready(refreshMasonry);
    
  • a masonry brickek container eleme legyen az infinity scroll elem is, és legyen relative a pozíciója:
    <div class="bricks" data-autopagination="{{feeditems.pagination.autopagination}}"  id="masonrycontainer">
  • az .ofw-watchelement legyen absolute pozíció a brickek container elemánek aljára pozícionálva:
    .ofw-watchelement{
      position: absolute;
      bottom: 10px;
      ... ... ....
    }
  • a masonry-t valahol zaj.ready()-ben hívd meg a refreshMasonry()-vel

Infinite scroll with button

If your page has a footer, it is not a good idea to implement automatic pagination via infinite scroll – this will make any content below the list inaccessible. Instead, you can add a “Load more results” button.

With a “Load more results” button, additional pages are not loaded when the user scrolls to the bottom of the list, but are instead loaded when the user clicks a specific button.

Simply create a button at the bottom of your list:

<a class="btn btn-load-more">Load more results</a>

Then, just add the data-autopagination-button data parameter to your container div. This parameter will need to set the CSS selector with which to find the “Load more results” button. Here’s an example for the button above:

<div data-autopagination="{{products.pagination.autopagination}}" data-autopagination-button=".btn-load-more">
Outlast Web & Mobile Development (c) 2023 | Privacy Policy |