Problem LoadMore Button

Hi, I would like to make a “Load More” button but I can’t make it work with my blog and to be honest I don’t really understand how it work, so there is “blog” (parent) and “blogarticle” (child).


template/blog.php*

<div class"main">
	<div class="articles" data-page="<?= $page->url() ?>" data-limit="<?= $limit ?>">
	<!-- Loop through the projects -->
      <?php foreach($page as $article): ?>
      <?php snippet('homearticle', compact('homearticle')) ?>
      <?php endforeach ?>
	</div>
	<button class="load-more">Load more</button>
</div>


template/blog.json.php*

<?php
$html = '';
foreach($page as $article) {
  // reuse the project snippet to create the HTML for each project
  // we need to set the third parameter to true, to return the
  // snippet content instead of echoing it
  $html .= snippet('homearticle', compact('homearticle'), true);
}
// add $html and $more to the $data array
$data['html'] = $html;
$data['more'] = $more;
// JSON encode the $data array
echo json_encode($data);
?>


snippets/homearticle.php*

<div class="HomeArticle">
	<a href="<?= $article->url() ?>"><?= $article->title() ?></a>
	<!--always check if the image exists!-->
	<?php if($coverimage =  $article->coverImage()->toFile()): ?>
		<a href="<?= $article->url() ?>"><img src="<?= $coverimage->url() ?>"></a>
	<?php endif ?>
</div>


controllers/blog.php*

<?php
return function($site, $pages, $page) {
  $article = $page->children()->visible()->filterBy('template', '==', 'blogarticle')->unscheduled();
  $count    = $article->count();
  // check if the request is an Ajax request and if the limit and offset keys are set
  if(r::ajax() && get('offset') && get('limit')) {
    // convert limit and offset values to integer
    $offset = intval(get('offset'));
    $limit  = intval(get('limit'));
    // limit projects using offset and limit values
    $page = $article->offset($offset)->limit($limit);
    // check if there are more projects left
    $more = $count > $offset + $limit;
  // otherwise set the number of projects initially displayed
  } else {
    $offset   = 0;
    $limit    = 2;
    $projects = $article->limit($limit);
  }
  return compact('offset', 'limit', 'article', 'more');
};
?>


assets/js/script.js*

$(function(){

  var element = $('.page');
  var url     = element.data('page') + '.json';
  var limit   = parseInt(element.data('limit'));
  var offset  = limit;

  $('.load-more').on('click', function(e) {

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

      if(data.more === false) {
        $('.load-more').hide();
      }

      element.children().last().after(data.html);

      offset += limit;

    });

  });

});

So if I understand, it will load the snippet that will add 2 more article in the div class=“articles”, but if we use limit instead of pagination, can we make the button load more disapear if there is no more article to load ? We can’t check if there are next page …

Thanks :upside_down_face:

Please follow the cookbook recipe, you have changed some variables/element names but are not using them consistently.

  • In template, you loop through $page, but $page is the current page, not your articles collection.
  • Then you pass a variable homearticle to the snippet that is nowhere defined.
  • In your controller, you define $article(which should actually be $articles), but then you suddenly define $page and $projects, where you should stick to the $article($articles) variable.
  • In your script, you look for an element with the class page, but that element doesn’t exist, it is called articles.

No, that is not necessary, you don’t need to check if there. are more pages, but you check if there are more articles.

I make changes but when I click on the button, there is nothing.


template/blog.php

<div class"main">
	<div class="articles"  data-page="<?= $page->url() ?>" data-limit="<?= $limit ?>">
		<!-- Loop through the projects -->
		<?php foreach($articles as $article): ?>
			<?php snippet('article', compact('article')) ?>
		<?php endforeach ?>
	</div>
	<button class="load-more">Load more</button>
</div>


template/blog.json.php

<?php
$html = '';
foreach($articles as $article) {
  // reuse the project snippet to create the HTML for each project
  // we need to set the third parameter to true, to return the
  // snippet content instead of echoing it
  $html .= snippet('article', compact('article'), true);
}
// add $html and $more to the $data array
$data['html'] = $html;
$data['more'] = $more;
// JSON encode the $data array
echo json_encode($data);
?>


snippets/article.php

<div class="HomeArticle">
	<a href="<?= $article->url() ?>"><?= $article->title() ?></a>
	<!--always check if the image exists!-->
	<?php if($coverimage =  $article->coverImage()->toFile()): ?>
		<a href="<?= $article->url() ?>"><img src="<?= $coverimage->url() ?>"></a>
	<?php endif ?>
</div>


controllers/blog.php

<?php
return function($site, $pages, $page) {
    $articles = $page->children()->visible()->filterBy('template', '==', 'blogarticle')->unscheduled();
    $count    = $articles->count();
    // check if the request is an Ajax request and if the limit and offset keys are set
    if(r::ajax() && get('offset') && get('limit')) {
        // convert limit and offset values to integer
        $offset = intval(get('offset'));
        $limit  = intval(get('limit'));
        // limit projects using offset and limit values
        $articles = $articles->offset($offset)->limit($limit);
        // check if there are more projects left
        $more = $count > $offset + $limit;
        // otherwise set the number of projects initially displayed
    } else {
        $offset   = 0;
        $limit    = 3;
        $articles = $articles->limit($limit);
    }
    return compact('offset', 'limit', 'articles', 'more');
};
?>


assets/js/script.js

$(function(){

  var element = $('.articles');
  var url     = element.data('page') + '.json';
  var limit   = parseInt(element.data('limit'));
  var offset  = limit;

  $('.load-more').on('click', function(e) {

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

      if(data.more === false) {
        $('.load-more').hide();
      }

      element.children().last().after(data.html);

      offset += limit;

    });

  });

});

What disturb me in the tutorial is that the page is called projects.php and project.php etc… my main page is blog.php and blogarticle.php

Are you loading jQuery? Put a console.log('click'); as first thing after load more on click to check if it registers the click event.

It doesn’t matter what your files are called.

There is a error message few sec after I click on the button.

(Thanks for you time)

The URL looks strange. Is you blog on the home page? Wondering why the blog part is missing…

If is is on the home page, you have to adapt the URL you call in the script slightly:

  var url     = element.data('page') + '/.json';

You know your thing, there are no more error but still nothing loaded :thinking:

Check what is in the request and what response you get in dev tools.

Make sure there are more articles that meet the condition of being visible and scheduled and with this template.

So I’ve try with only

$articles = $page->children()->visible();

And when I click that is the response, it looks like that limit and offset aren’t detected ?

Hm :thinking:; I think I have to see this in action. Could you provide a zip for download somewhere (send me a PM if you want).

The problems were the redirection in my error.php page and the route to avoid the /blog/ in the url, now it’s working :wink: