Load More with AJAX

I think the problem is how you pass these variables to your get method in your JS.

This is what you do

 $.get(url, { limit, offset }, function(data) {

But instead, you have to pass key/value pairs, otherwise the variables are not set:

$.get(url, { limit: limit, offset: offset }, function (data) {

Interesting, my eslinter converts it back to:

$.get(url, { limit, offset }, function(data) {

Even when i disable eslint and change it to

$.get(url, { limit: limit, offset: offset }, function (data) {

it still doesn’t seem to work.

I could share a link to the repo, would that help?

Yes, I sent you a private message.

Thanks for your help @texnixe. The load more is working.

I have run into another issue though. I am trying to use the load more when filtering.

controller/interviews.json.php

<?php

return function ($pages, $page) {
  
  $interviews = $page->children()->listed()->flip();

  if($designrole = param('designrole')) {
    $interviews = $interviews->filterBy('role', str_replace('-',' ',$designrole));
  }
  
  if($designlocation = param('designlocation')) {
    $interviews = $interviews->filterBy('location', str_replace('-',' ',$designlocation));
  }

  if($designcompany = param('designcompany')) {
    $interviews = $interviews->filterBy('company', str_replace('-',' ',$designcompany));
  } 
  
  $count = $interviews->count();

  $offset = intval(get('offset'));
  $limit  = intval(get('limit'));

  $interviews = $interviews->offset($offset)->limit($limit);

  $more = $count > $offset + $limit;

  return compact('offset', 'limit', 'interviews', 'more');
}; 

As you can see, depending on the URL param, I am filtering the interviews but this doesn’t seem to work.

Any idea where I’m going wrong here?

If the parameter is not sent with your Javascript get request, then the filtering won’t happen. BTW, there is now a nicer way to filter multiple parameters using when():

While the example uses query strings, this is of course also possible with parameters.

On a side note: Looks like your are loading jQuery just for the purposes of filtering your interviews, or is this just for testing? The same can be achieved with vanilla JS.

So I had a feeling it would be related. In the interviews.json.php template file, I am already filtering the based on the URL param but it would be possible that this page as it is not actually loaded it doesn’t have those params?

I also tried writing vanilla js but I got stuck with the .get request portion.

Also, I’ll give the $pages->when() a try.

I did some digging and found this Cookbook "Load more with Ajax" + filtering by url parameter but I’m struggling to get this to work, I think a part of it is missing.

Here are the steps:

  1. In your standard template, add data attributes for designrole, designcompany and designlocation
 <div class="interviews" 
        id="interviews" 
        data-page="<?= $page->url() ?>" 
        data-limit="<?= $limit ?>" 
        data-role="<?= $designrole ?>"
        data-company="<?= $designcompany ?>"
        data-location="<?= $designlocation ?>"

Note that you have to also adapt the controller to return these variables if they are set, so we use the long form instead of compact:

  return [
    'offset' => $offset, 
    'limit'  => $limit, 
    'interviews' => $interviews, 
    'more' => $more,
    'designcompany' => $designcompany ?? null,
    'designrole' => $designrole,
    'designlocation' => $designlocation,
  ];
  1. In your JS, get these attributes and send them with your request:
/*eslint-disable */
$(function() {
  const element = $('#interviews');
  const url = `${element.data('page')}.json`;
  console.log(url);
  const limit = parseInt(element.data('limit'));
  const designlocation = element.data('location');
  const designrole = element.data('role');
  const designcompnay = element.data('company');

  let offset = limit;
  $('.load-more').on('click', function(e) {
    $.get(url, { limit: limit, offset: offset, designrole: designrole, designcompany: designcompany, designlocation: designlocation }, function (data) {
      if (data.more === false) {
        $('.load-more').hide();
      }
      element
        .children()
        .last()
        .after(data.html);

      offset += limit;
    });
  });
});

The json controller needs some changes as well:

<?php

return function ($pages, $page) {
  
  $interviews = $page->children()->listed()->flip();

  if($designrole = get('designrole')) {
    $interviews = $interviews->filterBy('role', str_replace('-',' ',$designrole));
  }
  
  if($designlocation = get('designlocation')) {
    $interviews = $interviews->filterBy('location', str_replace('-',' ',$designlocation));
  }

  if($designcompany = get('designcompany')) {
    $interviews = $interviews->filterBy('company', str_replace('-',' ',$designcompany));
  }
  $count = $interviews->count();

  $offset = intval(get('offset'));
  $limit  = intval(get('limit'));

  $interviews = $interviews->offset($offset)->limit($limit);

  $more = $count > $offset + $limit;

  return [
    'offset' => $offset, 
    'limit'  => $limit, 
    'interviews' => $interviews, 
    'more' => $more,
    'designcompany' => $designcompany ?? null,
    'designrole' => $designrole,
    'designlocation' => $designlocation,
  ];
};

The important thing here is to use get() instead of param().

Makes a lot of sense! Thanks so much. Everything is working now :slight_smile:

could we have the final code for this in the cookbook? that would be great!

I guess that’s possible… :wink:

Once the team has approved, we will finally have an Ajax load more recipe again (free of jQuery).

4 Likes

thanks! i couldnt wait to test it :smiley: its working perfectly!

The final (and modified) version is now published:

1 Like

Works great. I adapted slightly for part of my own site to also ensure it works in a progressively enhanced way otherwise, if JavaScript is off (or not available), there’s no navigation.

The gist of the changes are: checking whether JS is on or not when the page loads (changes a pre-set class on the body element from “off” to on" if enabled), adding traditional pagination controls to the page and then, if JS is on, deciding which control to show with some CSS. Oh and I added an Accesskey control for the load more button so Control-M will fire the JS.

1 Like

Good idea, I think I will finally add that to the recipe as well.

1 Like

Sorry to bring up an old thread, is this recipe still meant to be working? I’m following it on a fresh starterkit and can’t get the load button to work.

Yes, it’s still supposed to work (and does work, tested in 3.9.6.1)

Are there any specific server requirements maybe, or anything hidden which I may missed? I’m running it on localhost. Json displays content if I open localhost/photography.json.php, but nothing happens on load more click.