Making a loading more link which displays more results with AJAX

Recommended Posts

Let's say I have 500 Eventpages or more with differen content fields(date, title, textarea etc..).

I would display all events in a list like this:

$events = $pages->find("template=event, limit=10");

echo "<div class='event-container'>";

foreach($events as $event){
    echo "<div class='event-detail'>

echo "<a class='load-more'>LOAD MORE</a>";
echo "</div>";

Now I want to make the load-more link to display 10 or 20 more events without reloading the page and showing a loading gif/text while its rendering the other events, when clicking on it . How can i achieve this? I know that i could use pagination for displaying this heavy amount of results but the customer doesn't want that because it don't fit in the design of the website. Can I probably achieve a combination with Pagination and Ajax, or are there other ways to do it?

Share this post

Link to post
Share on other sites

You may use one of those ready to use JS Libraries for Infinite Scrolling you can found on the net. One that I know and have used myself is IAS.

In PW you must use pagination as you explained above, also have to render the NEXT button, but with display:none in CSS to make it invisible. The JS-Script will pick it up and loads the next portion when the user scrolls down.

  • Like 4

Share this post

Link to post
Share on other sites

You may use one of those ready to use JS Libraries for Infinite Scrolling you can found on the net. One that I know and have used myself is IAS.

In PW you must use pagination as you explained above, also have to render the NEXT button, but with display:none in CSS to make it invisible. The JS-Script will pick it up and loads the next portion when the user scrolls down.

I have never really delved in to this, but would love to see a fully realized example using this method. I often stumble over how one manages manual page selection by the user for seo purposes. I would love to have a page with a combination of pagination and infinite scrolling. 

  • Like 2

Share this post

Link to post
Share on other sites

I have used it only one times. If it is of any help, I can paste in some code snippets here from that site. But it isn't an infinite only solution, it is bundled together with masonry.


JS parts:

// JS in every page that uses infinite scrolling
<script type='text/javascript'>
    var gLoaded = 0;
    var gMaxPages = 12;
    var gTriggerPageThreshold = 100;
    var gPaginationHistory = false;    // switch on / off URI updating for pages: example.com/path/page2 | /page3 | page4
    var gContainer = '#albums';
    var gItemSelector = 'article.album';
    var gColumnWidth = 228;         // 48
    var gGutter = 12;               // 12

    $(document).ready(function() {
        // make it visible if JS is supported

in an external JS file I have the functions for Masonry and IAS:

function starteIAS() {
        container            : gContainer,
        item                 : gItemSelector,
        pagination           : '.pagination',
        next                 : 'a.next-album',
        loader               : "<img src='/site/templates/styles/images/loader.gif' />",
        thresholdMargin      : -9,
        triggerPageThreshold : gTriggerPageThreshold,
        history              : gPaginationHistory,
        noneleft             : "<div class='ias_msg noneleft'><p>no more items available</p></div>",

        onLoadItems          : function(items) {
          // HNLOG
          console.log('IAS onLoadItems (' + gTriggerPageThreshold + ')');
            var newElems = $(items).show().css({ opacity:0 });
                $('#albums').masonry('appended', newElems);
                newElems.animate({ opacity:1 });
            return true;

function starteMasonry() {
    var items = $(gContainer + ' ' + gItemSelector).show().css({opacity:0});
        itemSelector         : gItemSelector,
        isOriginLeft         : true,
        isOriginTop          : true,
        columnWidth          : gColumnWidth,
        gutter               : gGutter,
        isAnimated           : true,        // !Modernizr.csstransitions
        isFitWidth           : true

The PHP looks like:

// calculate current amounts
$limit = 100;
$max	= $pages->find("$pSelector,limit=2")->getTotal();
$cur	= $input->pageNum;
$next   = ($cur * $limit) < $max ? $cur + 1 : 1;
$prev   = $cur > 1 ? $cur - 1 : 0;
$start  = $cur < 2 ? '0' : strval($limit * ($cur -1));

    // echo prev-next links for pagination  (only next is required, prev isn't used !!)
    $pagination = "<div style='display:none' class='pagination'>";  // hide it !!
        //if($prev > 0) $pagination .= " <a href='{$archivURL}page{$prev}'>prev</a> |";
        if($next > 1) {
            if(isset($nextPageUrl)) {
                $pagination .= " <a class='next-album' href='{$nextPageUrl}page{$next}'>next</a> ";
            } else {
                $pagination .= " <a class='next-album' href='{$archivURL}page{$next}'>next</a> ";
    $pagination .= "</div>\n";
    echo $pagination;

    // Hinweis zum scrollen
    echo "<div class='ias_msg scrolldown".($cur)."'><p>scroll down to get more items</p></div>";

    // get PageArray
    $albums = $pages->find("$pSelector, limit=$limit, start=$start, sort=sort");

    // output albums with thumbnail and infos
    foreach($albums as $album) {
        // ... render items

Using IAS, you even don't need to check for ajax request or not. just send the whole page, with header and body. The script knows the selectors and pick up the needed content and add it to the dom, after the last renderd from previuos request. Easy!

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By gerald
      In my frontend I would like to implement a small AJAX-solution, but it does´nt work. For example:
      template/js/ajax.js: contains jquery-ajax-snippet with click-function like this: $.post('ajax.inc', function(e) {});
      template/ajax.inc: contains db-query with HTML-output
      template/home.php: contains div-element for the ajax-response, e.g. <div id='result'>...ajax-response...</div>
      It seems, PW does´nt allow database-requests via AJAX (jquery). I know the post from Ryan "How to work with AJAX driven content in ProcessWire". But this solution requires a completely new template-concept. I only need a simple solution for a small ajax-db-request.
      Thanks to all
    • By cosmicsafari
      Hi all,
      I have been asked by a client whether we can setup load balancing for their existing Processwire site.
      From my investigations on Google and within these forums, it definitely seems possible but as a newbie with a basic understanding of the subject im a bit lost.
      Does anyone know of any existing tutorials for settings up load balancing with PW?
      What items would need to be changed on their current stand alone install, is there a list of best practices worth consulting etc?
      As I understand it we would need to have some sort of copying mechanism (rsync script most likely) in order to make sure any uploaded assets are shared between the main server and the fallback ones, other than that im not sure what else would need to be ammended.
      Any thoughts/help would be greatly appreciated.
    • By usualCommission
      Hey everyone,
      I'm pretty experienced with pagination and haven't seen this before. I have my pages pulled using $pages->find, which is working fine however using renderPager() generates pagination where the links do not work. Here are some details.
      All templates needing pagination have pagination enabled in the admin. URL Segments are not enabled. Clicking on the "Next" or numbered links merely reloads the current page. The link href values are properly being output with the urls being /page2, /page3, /page4, etc. Manually entering the paginated urls has the same effect of reloading the current page with no new content. Pages are being returned from the ->find function properly and with the proper limit. A few other details:
      ProcessWire v3.0.98 Multi-language is enabled, 2 languages implemented. Pagination does not work on either language Have very few modules installed (few enough to list), none of which I could see interfering: ProFields, ProDrafts, ListerPro, DB Backups, Cronjob DB Backup, Upgrades, Upgrade Checker, Force Password Change, Markup Sitemap XML I'm stumped. For the sake of being overly-thorough, here's the code:
      <?php $articleTemplates = [ 'template_news_article', 'template_news_video', 'template_news_press_release' ]; $searchParams = [ 'template=' . implode('|', $articleTemplates), 'sort=-published', 'limit=' . $pages->get('template=template_news')->list_count ]; $articles = $pages->find(implode(',', $searchParams)); echo $articles->renderPager(); ?>  
    • By Mobiletrooper
      Hey Ryan, hey friends,
      we, Mobile Trooper a digital agency based in Germany, use ProcessWire for an Enterprise-grade Intranet publishing portal which is under heavy development for over 3 years now. Over the years not only the user base grew but also the platform in general. We introduced lots and lots of features thanks to ProcessWire's absurd flexibility. We came along many CMS (or CMFs for that matter) that don't even come close to ProcessWire. Closest we came across was Locomotive (Rails-based) and Pimcore (PHP based).
      So this is not your typical ProcessWire installation in terms of size.
      Currently we count:
      140 Templates (Some have 1 page, some have >6000 pages)
      313 Fields
      ~ 15k Users (For an intranet portal? That's heavy.)
      ~ 195 431 Pages (At least that's the current AUTOINCREMENT)
      I think we came to a point where ProcessWire isn't as scalable anymore as it used to be. Our latest research measured over 20 seconds of load time (the time PHP spent scambling the HTML together). That's unacceptable unfortunately. We've implemented common performance strategies like:
      We're running on fat machines (DB server has 32 gigs RAM, Prod Web server has 32gigs as well. Both are running on quadcores (xeons) hosted by Azure.
      We have load balancing in place, but still, a single server needs up to 20 sec to respond to a single request averaging at around about 12 sec.
      In our research we came across pages that sent over 1000 SQL queries with lots of JOINs. This is obviously needed because of PWs architecture (a field a table) but does this slow mySQL down much? For the start page we need to get somewhere around 60-80 pages, each page needs to be queried for ~12 fields to be displayed correctly, is this too much? There are many different fields involved like multiple Page-fields which hold tags, categories etc.
      We installed Profiler Pro but it does not seem to show us the real bottleneck, it just says that everything is kinda slow and sums up to the grand total we mentioned above.
      ProCache does not help us because every user is seeing something different, so we can cache some fragments but they usually measure at around 10ms. We can't spend time optimising if we can't expect an affordable benefit. Therefore we opted against ProCache and used our own module which generates these cache fragments lazily. 
      That speeds up the whole page rendering to ~7 sec, this is acceptable compared to 20sec but still ridiculously long.
      Our page consists of mainly dynamic parts changing every 2-5 minutes. It's different across multiple users based on their location, language and other preferences.
      We also have about 120 people working on the processwire backend the whole day concurrently.
      What do you guys think?
      Here are my questions, hopefully we can collect these in a wiki or something because I'm sure more and more people will hit that break sooner than they hoped they would:
      - Should we opt for optimising the database? Since >2k per request is a lot even for a mysql server, webserver cpu is basically idling at that time.
      - Do you think at this point it makes sense to use ProcessWire as a simple REST API?
      - In your experience, what fieldtypes are expensive? Page? RepeaterMatrix?
      - Ryan, what do you consider as the primary bottleneck of processwire?
      - Is the amount of fields too much? Would it be better if we would try to reuse fields as much as possible?
      - Is there an option to hook onto ProcessWires SQL builder? So we can write custom SQL for some selectors?
      Thanks and lots of wishes,
      Pascal from Mobile Trooper
    • By louisstephens
      So I was going to build a todo tracking app for myself to test/broaden my knowledge of processwire, and so far it has been taxing 😓.  My Site structure is:
      - Project One - Phase One - Task - Task - Task - Phase Two - Task - Task - Task So far it was pretty easy, I can easily foreach through the Project and get the phases with their tasks. However, it gets a bit muddled when I have more than one project as I was trying to have a dashboard where the content switches out to the selected project as opposed to accessing each project via their own url. How would yall handle this?
      My next hurdle is each task has a select field (for project status) that I want to update via ajax (for the smooth transitioning).
      Scenario: You finish a task, change the option from "new" to "completed", and an onclick changes the status drop down background to green (which I have working), but then posts/saves a field on the backend to the new option.
      I have a page called "Actions" set up with url segments using
      if ($config->ajax && $input->urlSegment1 == 'change-status') { //save update field on admin } However, I am a little fuzzy on how to actually pass the current page along with the new selected status to actually update the page (task). I guess I am not very far into my endeavor. Any help would be greatly appreciated.