How to: Dynamic Pagination (without page reload)?

The scenario is: the blogroll on a site is loading a paginated list of 4 articles at a time. Below it, there are the usual prev/next arrows, which currently reload the entire page - repopulating the list with the appropriate new articles. I’d like to avoid the page reload, and have just the list with the new 4 articles reload, via ajax.

Is there a way to perhaps manually ‘move’ forward/backward through the pagination object, without actually reloading the page? I thought if I could get the ‘next 4’ or ‘prev 4’ articles as a $pages collection, I could repopulate the list via jQuery…

Could someone point me in the right direction?..

What you could do is the following:

  • If you don’t already have one, create a controller for your blog template.
  • In that controller, check for r::ajax(). It will return true if the request has been made using AJAX.
  • If the request is an AJAX request, only return a snippet of the respective articles for the passed pagination page instead of returning the full template. Make sure to include the pagination in the returned snippet however, because that will change as well. :wink:
  • Replace the articles dynamically with the new ones using JavaScript.

Your JavaScript code would just need to listen on the “click” events for the pagination links and send an AJAX request instead of reloading the page. Since the links contain the pagination page, you shouldn’t need to manually grab the items.

And of course, you should first make working links (no JS, working URLs) and then add the JS alternative on top.

Also if you replace the pagination block (for instance if it’s a list of numbers instead of a “Show more” button) as suggested by Lukas, note that it will kill your event listener (since you remove the elements that had attached event listeners). The usual solution for that is to use event delegation.

That’s why my solution uses a controller that checks if the request is an AJAX request. It means that the link will work just fine without JS.

Thank you for your guidance, guys. A couple of things are not clear to me:

How can the controller in this case control whether a full page or a snippet gets returned? Don’t controllers merely return variables to be used in the template, and the template determines what gets returned? Sorry for my confusion…

Do you mean, that we should pass an $articles->paginate(4) object to the snippet, rather than merely an $articles?

Yes, that’s normally what controllers do. But you can use something like this:

<?php

return function($site, $pages, $page) {
  $items = $page->children()->visible()->paginate(4);

  // catch ajax
  if(r::ajax()) die(snippet('articles', compact('items')));

  // not ajax, return the items to the template
  return compact('items');
};

That too, but what I meant was that you need to output the HTML for the pagination even when the request is an AJAX request so that the links are correct after changing pages.

1 Like

@lukasbestle BIG thank you for the lesson on using a controller to ‘filter’ the ajax calls - that’ll be useful in many other scenarios. I got it all working! Yay!!! :smiley:

1 Like

@luxlogica Is it possible that you could post the code for your solution here? I try to do something like your solution but I’m not so good with Ajax.
I would appreciate it very much.

hello everyone ,
i have also same problem. i also want to code like load more.
is there anyone have working demo for it? :slight_smile: