0

I have a script in javascript that load more information on page scroll down. The problem is that when I scroll down the script is executed twice and I have the same result twice or even more.

I want to execute the script once each time I scroll down and not execute it twice or even more each time.

This is the script:

$(window).scroll(function(){
   
        var lastID = $('.load-more').attr('lastid');
        if ($(window).scrollTop() == $(document).height() - $(window).height() && lastID != 0){
            $.ajax({
                type:'POST',
                url:'getdata.php',
                data:'id='+lastID,
                beforeSend:function(html){
                    $('.load-more').show();
                },
                success:function(html){
                    $('.load-more').remove();
                    $('#list').append(html);
                }
            });
        }
    });
  
Funk Forty Niner
  • 74,450
  • 15
  • 68
  • 141
Dilak
  • 43
  • 1
  • 2
  • 8

5 Answers5

0
$(window).one('scroll',function(){ ...}
..

Explanation of "one" from jquery docs: The handler is executed at most once per element per event type. http://api.jquery.com/one/ Function will execute only first time you scroll, nothing will happen second time nor any subsequent time.

Killer Death
  • 459
  • 2
  • 10
0
var timeout;

$(window).scroll(function() {
  clearTimeout(timeout);  
  timeout = setTimeout(function(){

    var lastID = $('.load-more').attr('lastid');
    if ($(window).scrollTop() == $(document).height() - $(window).height() && lastID != 0){
        $.ajax({
            type:'POST',
            url:'getdata.php',
            data:'id='+lastID,
            beforeSend:function(html){
                $('.load-more').show();
            },
            success:function(html){
                $('.load-more').remove();
                $('#list').append(html);
            }
        });
    }
 }, 200);
});

Second execution of scroll will trigger cancelling of function delayed execution and initiate another execution which will not be cancelled by anything.

Killer Death
  • 459
  • 2
  • 10
0

You could wait until the previous one is done loading before loading a new one.

var isLoading

$( window ).on( 'scroll', onScroll )

function onScroll() {

  if( isLoading ) return

  isLoading = true

  $.ajax({
    success: function() {

      isLoading = false

      // Add content, etc...

    }
  })

}
flcoder
  • 713
  • 4
  • 14
  • If function is executed quickly, it will still be executed twice. – Killer Death Aug 29 '17 at 23:06
  • @Killer Death Javascript is single threaded. Your fiddle code always exits with isLoading = false. My code NEVER exits with isLoading = false. That's a huge difference. – flcoder Aug 29 '17 at 23:51
  • True, but isLoading will be set to false after successful async response, it assures that a second async call is prevented before first one finishes, he wants to prevent second event handler from firing reguardless of that. – Killer Death Aug 30 '17 at 05:39
  • I'm not sure that is the case here: "I want to execute the script once each time I scroll down" – flcoder Aug 30 '17 at 20:57
  • Your solution is pretty similar to this actually. It also allows more than one ajax call. The only difference between your solution and this is that this does not create any objects which is what timeouts are, this is not calling any functions like clearTimeout or setTimeout, and this is not causing any delay between the moment the user starts scrolling and when the ajax call is sent, whereas your solution forces the ajax call to hold off for 50-200 ms after the user stops scrolling. I think it makes more sense to fire the ajax asap and then ignore scroll events until it's complete. – flcoder Aug 30 '17 at 21:15
0

Try this

var counter  = 0;


 $(window).scroll(function(){

        var lastID = $('.load-more').attr('lastid');
        if ($(window).scrollTop() == $(document).height() - $(window).height() && lastID != 0 && counter < 1){
            counter++;
            $.ajax({
                type:'POST',
                url:'getdata.php',
                data:'id='+lastID,
                beforeSend:function(html){
                    $('.load-more').show();
                },
                success:function(html){
                     // reset counter to 0 after you get your results
                    counter = 0;
                    $('.load-more').remove();
                    $('#list').append(html);
                }
            });
        }
    });
TimCodes
  • 365
  • 2
  • 14
0

Add one more test so you ignore scroll if your loader is showing

if (
    $(window).scrollTop() === $(document).height() - $(window).height()

    && +lastID !== 0

    // fancy way to say "Is this element in the DOM" w/ good performance
    && $.contains(document.documentElement, $('.load-more')[0])
) {

  // then load more content

}

Mini-Rant:

I changed == to === and I explicitly coerced lastID to a number, which also allowed changing != to !==.

It's simply good habit to avoid automatic type coercion when it doesn't provide any obvious benefit. There is nothing inherently bad about this language feature. However, taking reasonable steps to avoid it when you can will make your code easier to understand and easier for the jit compiler to optimize. When I find something like == in my own code, it's appearance is self-documenting, letting me know I intentionally leveraged type coercion for a purposeful effect (other saving 1 little keystroke).

Note: Selected method for checking element existence came from jsPerf provided by SLaks in his comment to this answer.

skylize
  • 1,401
  • 1
  • 9
  • 21