6

I load data into my DIV with AJAX using 3 different functions. I am trying to prevent multiple AJAX calls when the browser scroller remains at the bottom of the DIV that I am lazy-loading data into.

This works but sometimes (just sometimes) the scroller remain at the bottom of my div and this will cause many AJAX calls to happen. How do I prevent that from happening?

$(document).ready(function() {

    //form submit by click
    $("#submit").click(function(e) {
        // Prevent Default Action In Case to Load data by form
        e.preventDefault();

        //prevent select to post empty data
        $('select').each(function() {
            if ($(this).val() == '') {
                $(this).attr('disabled', 'disabled');
            }
        });

        // Define what we need
        var loading = "<img src='/zojfa/images/loading.gif' alt='Loading...' />";
        var scrolltop = $('#scrollbox').attr('scrollTop');
        var scrollheight = $('#scrollbox').attr('scrollHeight');
        var windowheight = $('#scrollbox').attr('clientHeight');
        var post = $(this).attr("name") + "=" + $(this).val();
        var form_data = $('#search_form').serialize() + "&" + post;
        var scrolloffset = 20;

        //empty content if another value sent to code
        $('#content').empty();
        //load data
        loaddata(form_data, 0);
    });

    //listen to scroll function
    $('#scrollbox').scroll(function() {

        //define what we need
        var scrolltop = $('#scrollbox').attr('scrollTop');
        var scrollheight = $('#scrollbox').attr('scrollHeight');
        var windowheight = $('#scrollbox').attr('clientHeight');
        var scrolloffset = 20;

        //get number of div which will append to script in case of limit database to page 2 or 3 or...
        size = $('#content > div').children().size();



        //if we reach to bottom of div we are going to call to ajax function
        if (scrolltop >= (scrollheight - (windowheight + scrolloffset))) {
            var form_data = $('#formdata').val();

            //if remain of size(count of div) is 0 then we have more data to show because we limit data provided by script to 7 field(we handle situation that we had 14 or 21 respond from database in "next step" because if there is no data to show we dont have to let script to run)
            if (size % 7 == 0) {
                //call to load data function
                setTimeout(function() { loaddata(form_data, size) }, 1500);
            } else {
                //do nothing its just in case we need to append something like no more data to load
            }
        }
    });

    // page load finish
});


//function to load data
function loaddata(form_data, size) {
    number = "&size=" + size;
    //fetch new items
    $.post('dosearch.php', form_data + number, function(newitems) {
        //next step : if page echoing "" then do nothing
        if (newitems == '') {} else {
            //if we have data append these data to our div's #content
            $('#content').append(newitems);
        }
    });
}​

update

I did just as dear @Kent Pawar and dear @E.J. Brennan said but now I get more AJAX calls when I reach to bottom of the div and it still doesn't quite work.

$("#submit").click(function(e) {
    // Do some Default
    e.preventDefault();

    $('select').each(function() {
        if ($(this).val() == '') {
            $(this).attr('disabled', 'disabled');
        }
    });

    // var what we need
    var loading = "<img src='/zojfa/images/loading.gif' alt='Loading...' />";
    var scrolltop = $('#scrollbox').attr('scrollTop');
    var scrollheight = $('#scrollbox').attr('scrollHeight');
    var windowheight = $('#scrollbox').attr('clientHeight');
    var post = $(this).attr("name") + "=" + $(this).val();
    var form_data = $('#search_form').serialize() + "&" + post;
    var scrolloffset = 20;

    $('#content').empty();

    //load data
    loaddata(form_data, 0);
    $('select').each(function() {
        if ($(this).val() == '') {
            $(this).removeAttr('disabled');
        }
    });
});


$('#scrollbox').scroll(function() {
    //var what we need
    var scrolltop = $('#scrollbox').attr('scrollTop');
    var scrollheight = $('#scrollbox').attr('scrollHeight');
    var windowheight = $('#scrollbox').attr('clientHeight');
    var scrolloffset = 20;

    // when we reach
    size = $('#content > div').children().size();

    if ($('#scrollbox').data('ajaxready') === false)
        return;

    if (scrolltop >= (scrollheight - (windowheight + scrolloffset))) {
        $('#scrollbox').data('ajaxready', false);
        var form_data = $('#formdata').val();

        if (size % 7 == 0) {
            setTimeout(function() { loaddata(form_data, size) }, 1500);
        } else {

        }
    }
    $('#scrollbox').data('ajaxready', true);

    // page load finish
});

function loaddata(form_data, size) {
    number = "&size=" + size;
    //fetch new items
    $.post('dosearch.php', form_data + number, function(newitems) {
        if (newitems == '') {} else {
            $('#content').append(newitems);
        }
    });
}
JustCarty
  • 3,839
  • 5
  • 31
  • 51
HiDd3N
  • 494
  • 6
  • 23
  • 1
    Are you trying to achieve something like Facebook's lazy load where it loads the previous post as the user scrolls down? – Kent Pawar Dec 09 '12 at 15:02
  • yes.i achieve this but sometimes(just in mozzila not in chrome)scroller remain in bottom of div which will cause many ajax call – HiDd3N Dec 09 '12 at 15:09
  • 1
    Could you improve the comments in your code. It would attract more eyeballs.. :) Thanks. Not sure what is happening in the scroll event handler... – Kent Pawar Dec 09 '12 at 15:20
  • When exactly does the scroller remain in bottom of the DIV#scrollbox? Is it when there is no more data to be loaded? – Kent Pawar Dec 09 '12 at 15:24
  • Kent Pawar realy thanks for help.. code updated – HiDd3N Dec 09 '12 at 15:29
  • no when i call to $("#submit").click(function(e){ – HiDd3N Dec 09 '12 at 15:32

2 Answers2

7

Well the issue isn't with the scroller being at the bottom of the page but with the way the event handler works. There are times the scroller would be at the bottom of the page like say when there are no more post to load... observe Facebook's wall for example.

Currently, the JQuery scroll event is triggered when scrolling occurs.

JQuery docs:

A scroll event is sent whenever the element's scroll position changes, regardless of the cause. A mouse click or drag on the scroll bar, dragging inside the element, pressing the arrow keys, or using the mouse's scroll wheel could cause this event.

Now its the job of your script to make a single AJAX call to check if there is content to be loaded. You need to modify your script to stop multiple AJAX calls from taking place during this time and as I see @E.J. Brennan has already suggested the same :).

You could add the flags as follows:

//listen to scroll function
  $('#scrollbox').scroll(function(){

        //[Kent] Before we service the event, we check if the last scroll event was handled/completed.
        //If it is not yet compelted, don't start another one and jump out of the code.
        if ($(window).data('ajax_in_progress') === true)
            return;

        //define what we need
        var scrolltop=$('#scrollbox').attr('scrollTop');
        var scrollheight=$('#scrollbox').attr('scrollHeight');
        var windowheight=$('#scrollbox').attr('clientHeight');
        var scrolloffset=20;

        //get number of div which will append to script in case of limit database to page 2 or 3 or...
        size =  $('#content > div').children().size();

        //if we reach to bottom of div we are going to call to ajax function
        if(scrolltop>=(scrollheight-(windowheight+scrolloffset))){
            $(window).data('ajax_in_progress', true);  //[Kent] prevent more scroll events as AJAX request will soon begin. 

            var form_data = $('#formdata').val();

            // if remain of size(count of div) is 0 then we have more data to show because 
            // we limit data provided by script to 7 field(we handle situation that we had 
            // 14 or 21 respond from database in "next step" because if there is no data to 
            // show we dont have to let script to run)
            if(size % 7 == 0){
                //call to load data function
                setTimeout(function(){loaddata(form_data, size)}, 1500);
            }else{
                //do nothing its just in case we need to append something like no more data to load
            }
        }
    });    



//function to load data
function loaddata(form_data, size){
    number = "&size=" + size;
    //fetch new items
    $.post('dosearch.php', form_data+number, function(newitems){
        // [Kent] This is the callback funciton that gets executed ONLY
        // when the AJAX request has completed. We will append the data
        // into the DOM and then reset the FLAG.

        //next step : if page echoing "" then do nothing
        if(newitems == ''){
        }else{
            //if we have data append these data to our div's #content
            $('#content').append(newitems).each(function() {
                //Adding a callback to append.
                // So we reset the flags here to indicate the scroll event 
                // has been handled/completed and so we turn scrolling events back on
                $(window).data('ajax_in_progress', false);
            });
        }
    });
}   
Kent Pawar
  • 2,378
  • 2
  • 29
  • 42
  • the problem didnt solve by E.J. Brennan recommendation.i think problem with firefox is being so fast in localhost area.and being fast will cause this scroller to dont go to top when data loaded and remain in bottom of div.realy thanks and +1 for you to help me but no joy in using flags..but maybe i did something wrong about flags. i dont know – HiDd3N Dec 09 '12 at 16:02
  • @HiDd3N Well flags are definitely required as different browsers would fire the scroll event differently. You could update your code again... – Kent Pawar Dec 09 '12 at 16:08
  • thanks :) i add lines for scroll function but no ajax call after adding this lines – HiDd3N Dec 09 '12 at 16:18
  • thanks dear Kent Problem solved just another question to get it more.is this .data() can be used in every function.its public for all functions? – HiDd3N Dec 09 '12 at 16:38
  • 1
    Your welcome. data() is a JQuery event handler. It can be used to attach/store data for ANY DOM object. It's explained here -> [jQuery.data](http://api.jquery.com/jQuery.data/) – Kent Pawar Dec 09 '12 at 17:03
  • 1
    Please don't make [suggested edits like this](http://stackoverflow.com/review/suggested-edits/1154087); see the rejection reasons at the top as to why, but generally, don't change the intent of the author. You should comment @ the author indicating these things, and give the author the first chance to make the edit. – casperOne Dec 09 '12 at 18:21
5

Not 100% clear on your exact problem, but I also had similar problems with firefox firing loads of scroll events before the first one even completed, whereas chrome did not.

What I did was add a flag when I started loading new data (from ajax) and unset the flag when it completed, and this solved my problem.

Something like this:

    $(window).scroll(function () {

    //if last scroll is not done, don't start another one.
    if ($(window).data('ajaxready') === false)
        return;

    if ($(window).scrollTop() >= $(document).height() - $(window).height() - 100) {
        $(window).data('ajaxready', false);  //prevent more scroll events
        YourFunctionCallToGetGetMoreData();  //go get the data here.
    }

    //turn scrolling events back on
    $(window).data('ajaxready', true);
});

in your case, the call to turn the scrolling back one would go in the callback function of the ajax data load.

E.J. Brennan
  • 45,870
  • 7
  • 88
  • 116