1

I am using a template which has a 'LOAD MORE' button beneath a grid of entries (entries 1-10). Click this link loads addition content to the grid via AJAX from another page (which contains entries 11-20). There is also a second page which has entries 21-30. The code looks like this:

<div class="load-isotope align-center">
  <a  href="p2.html" class="sr-button" 
    data-related-grid="artefact-grid" 
    data-method="loadonclick">Load More</a>
  <span class="load-message">No more items to show</span>
</div>

There is JS that will change the p2.html to p3.html when it is clicked, so the second time the button is click the 3rd set of entries is added.

I would like some help as to how to change the JS to make this work with craft pagination. I can add

{{ paginate.nextUrl ~ queryString }}

as the target URL which works for the first click (the link is rendering out as URL/section/p2 and the content is added via AJAX in the correct place) but I need this to change to /p3 etc with each click.

It seems as though the LOAD MORE function in the JS is mentioned in 2 places:

/* isotope load more function
------------------------------------------------*/
function isotopeLoadMore(grid,el,url,datas) {

  el.parent(".load-isotope").addClass('loading');

  if (url === '#' || !url) { url = srvars.ajaxurl }
  var addData = ''; if (datas) { addData = { action:'sr_load_more', o:datas }; }
  jQuery.ajax({
    type:'POST',      // this might lead to issues for html template
    url:url,
    data: addData,
    dataType:"html",
    error: function () {
      el.parent(".load-isotope").addClass("disabled");  
    },
    success: function(response) { 
      //console.log(response);
      if (response) {
        setTimeout(function(){ 
          var items = jQuery( jQuery(response).find('#'+grid.attr('id')).html());
          items.imagesLoaded(function(){
            grid.append( items ).isotope( 'appended', items);
            animateOnScroll(false);
            // init video bg for appended items
            if(jQuery().phatVideoBg) { grid.find('.videobg-section').phatVideoBg(); }
          });
          el.parent(".load-isotope").removeClass('loading');
        },500);
      } else {
        el.parent(".load-isotope").addClass("disabled");  
      }
    }
  });

}

AND:

/* Load More isotope
------------------------------------------------*/
var loadMore = jQuery('.load-isotope:not(.disabled) a');

loadMore.click(function(){      
  var el = jQuery(this);
  if(el.data("loadpage") === undefined) { el.data("loadpage","2"); }
  else { el.data("loadpage", parseInt(el.data("loadpage"),10)+1); }
  var   related = el.data('related-grid');
  var   href = el.attr('href').replace("/2", '/'+el.data("loadpage"));
  href = href.replace("2", el.data("loadpage"));
  var datas = '';
  if(el.data("options") !== undefined && el.data("options")) { datas = el.data('options').replace("paged=2", "paged="+el.data("loadpage")); }
  isotopeLoadMore(jQuery('#'+related),el,href,datas);
  return false;
});

Any help with this would be massively appreciated

1

Could you just append a new "load more" button to the page as part of the requested AJAX template and remove the old one when it's successfully loaded?

Each load more button might look something like this:

{% if paginate.nextUrl %}
  <a href="{{ paginate.nextUrl ~ queryString }}" class="sr-button" 
     data-related-grid="artefact-grid" 
     data-method="loadonclick">Load More</a>
{% endif %}

Then in your isotopeLoadMore() function, you can remove the load more button that was clicked on if you get a successful response and replace it with a button from the AJAX response. Something like this:

/* isotope load more function
------------------------------------------------*/
function isotopeLoadMore(grid,el,url,datas) {

  // create a var for the button's parent so we can reuse it
  var loadIsotope = el.parent(".load-isotope")
  loadIsotope.addClass('loading');

  if (url === '#' || !url) { url = srvars.ajaxurl }
  var addData = ''; if (datas) { addData = { action:'sr_load_more', o:datas }; }
  jQuery.ajax({
    type:'POST',      // this might lead to issues for html template
    url:url,
    data: addData,
    dataType:"html",
    error: function () {
      loadIsotope.addClass("disabled");  
    },
    success: function(response) { 
      //console.log(response);
      if (response) {
        setTimeout(function(){ 
          var items = jQuery( jQuery(response).find('#'+grid.attr('id')).html());
          // Find the new Load More button in the response
          var loadMode = jQuery( jQuery(response).find('.load-isotope').html());
          items.imagesLoaded(function(){
            grid.append( items ).isotope( 'appended', items);
            // add the new Load More button
            loadIsotope.append( loadMode );
            // remove the original Load More button
            el.remove();
            animateOnScroll(false);
            // init video bg for appended items
            if(jQuery().phatVideoBg) { grid.find('.videobg-section').phatVideoBg(); }
          });
          loadIsotope.removeClass('loading');
        },500);
      } else {
        loadIsotope.addClass("disabled");  
      }
    }
  });

}

But you'll have to attach your 'click' handler a little differently to make sure the dynamically loaded buttons will fire the same click function.

So instead of using...

var loadMore = jQuery('.load-isotope:not(.disabled) a');

loadMore.click(function(){ ...

That code will only attach the click function once when the page loads to the first button, but not any buttons that are dynamically added to the page thru your AJAX call.

Here's an example JSFiddle of a script that creates buttons and an alert. Only the original button works. New buttons don't do anything.

https://jsfiddle.net/alexroper/0aup8e5d/

But this JSFiddle uses delegated events like this...

$('.load-isotope').on('click', '.sr-button' ,function(event){ ...

... to attached click events to any $('.sr-button') element that's a child of $('.load-isotope'):

https://jsfiddle.net/alexroper/uq613627/1/

It's a similar problem to this Stack Overflow question: Jquery event handler not working on dynamic content

So here's a stab at what that might look like in your code. I'm not totally sure what everything in your code does, so you still may have to tweak it.

$('.load-isotope').on('click', '.sr-button' ,function(event){
  event.preventDefault();
  var el = $(this);
  var related = $('#' + el.data('related-grid'));
  var href = el.attr('href')
  var datas = '';
  if ( ! el.parents('.load-isotope').hasClass('disabled') ) {
    isotopeLoadMore(related,el,href,datas);
  }
});
  • Hi, Thanks for your response. This is where my knowledge is struggling. For what I understand you're suggesting that the when the ajax content is called the button should also be refreshed and therefore the url (for the next paginated content) will also be updated? That would make sense. However what is the JS you provided doing exactly? – Scott Robinson Feb 16 '17 at 12:48
  • I'm suggesting the original load more button that was clicked gets removed completely and a new load more button gets loaded by AJAX. So an AJAX request for the same button from the URL /p2 would render {{ paginate.nextUrl }} as href="/p3". The JS I wrote above isn't complete because I don't know everything you scripts are trying to do. I'll try to flesh it out more with some more explanations. – Alex Roper Feb 16 '17 at 20:24
  • Alex, Thank you so much for giving such a detailed response. That is seriously awesome. The only issue was the href was cycling back to the beginning but I put the button in a {% if paginate.nextUrl %} and it works perfectly. I have been seriously struggling with getting a working version of ajax pagination up on my site ... you have resolved my one big headache, so thank you again. – Scott Robinson Feb 17 '17 at 10:15
  • Awesome. I'll update my answer with that conditional. if this answer has solved your question please consider accepting it by clicking the check-mark. This indicates to the wider community that you've found a solution and gives some reputation to both the answerer and yourself. There is no obligation to do this. – Alex Roper Feb 17 '17 at 18:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.