Question

I'm having hard time figuring how to avoid duplicate ajax call for my infinite scroll javascript code. It mostly works but sometimes i have 2 or 3 times the same ajax page call causing a sort of loop. How to avoid this? Thanks

//infiniteScroll
var currentPage = 1;
var intervalID = -1000;
var scroll = false;

$('document').ready(function(){
    if ( scroll == true) {
        if (window.location.pathname == "/" && window.location.search == "" && $('#items_container').length > 0) {
            $('.pagination').hide();
            intervalID = setInterval(checkScroll, 300);
        }
    };
})

function checkScroll() {
  if (nearBottomOfPage()) {
        currentPage++;
    jQuery.ajax('?page=' + currentPage, {asynchronous:true, evalScripts:true, method:'get', 
        beforeSend: function(){
            var scroll = false;
            $('.spinner').show();               
        },
        success: function(data, textStatus, jqXHR) {
            $('.spinner').hide();
            $('#items_container').append(jQuery(data).find('#items_container').html());
            var scroll = true;
            if(typeof jQuery(data).find('.item').html() == 'undefined' || jQuery(data).find('.item').html().trim().length == 0 || currentPage == 10){
                clearInterval(intervalID);
        }
    },});
  }
}
}

function nearBottomOfPage() {
  return scrollDistanceFromBottom() < 450;
}

function scrollDistanceFromBottom(argument) {
  return pageHeight() - (window.pageYOffset + self.innerHeight);
}

function pageHeight() {
  return Math.max(document.body.scrollHeight, document.body.offsetHeight);
}
Was it helpful?

Solution

It looks like the checkScroll function is being called every 300 milliseconds, and it's possible that an AJAX request will take longer than that.

I see you've got the scroll variable, but you are only checking the value of it on the initial document load, which won't affect the timer.

I would suggest having a look at listening to the scroll event instead of creating a timer: jQuery docs. You could then do something like the following to prevent two ajax calls running:

var ajaxRunning = false;

function checkScroll() {
    if (!ajaxRunning && nearBottomOfPage()) {
        currentPage++;

        ajaxRunning = true;

        jQuery.ajax('?page=' + currentPage, {asynchronous:true, evalScripts:true, method:'get', 
        beforeSend: function(){
            $('.spinner').show();               
        },
        success: function(data, textStatus, jqXHR) {
            $('.spinner').hide();
            $('#items_container').append(jQuery(data).find('#items_container').html());
            if(typeof jQuery(data).find('.item').html() == 'undefined' || jQuery(data).find('.item').html().trim().length == 0 || currentPage == 10){
                clearInterval(intervalID);
        },
        complete: function() {
            ajaxRunning = false;
        }
    },});
  }
}

OTHER TIPS

Set async to false, or create a variable like

var isLoading = false;

In before send set it to true. On success set it false again. And before sending the ajax call, check if isLoading isn't true. If it is, return out of the function or put a loop inside with a spinner, which will be checking for the isLoading value so it fires the ajax first after isLoading was set to false.

Example:

function checkScroll() {
  if (nearBottomOfPage() && isLoading === false) {
    currentPage++;

    jQuery.ajax('?page=' + currentPage, {asynchronous:true, evalScripts:true, method:'get', 
    beforeSend: function(){
        var scroll = false;
        $('.spinner').show();
        isLoading = true;               
    },
    success: function(data, textStatus, jqXHR) {

        $('.spinner').hide();
        $('#items_container').append(jQuery(data).find('#items_container').html());
        var scroll = true;
        if(typeof jQuery(data).find('.item').html() == 'undefined' || jQuery(data).find('.item').html().trim().length == 0 || currentPage == 10){
          clearInterval(intervalID);
          isLoading = false;
        }
    },
  });
  }}}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top