anthonypliu
anthonypliu

Reputation: 12437

How to stop listening on event until ajax request is done

I am creating a 'scroll to bottom' news feed that populates news when the user scrolls to the bottom of the page.

I have the following code (via Check if a user has scrolled to the bottom):

$(window).scroll(function() {
   if($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
       //Ajax Request
   }
});

How can I make sure that a user does not scroll up and then scroll down again before the ajax request is done to populate the news. In other words whats a clean way to pause it until the ajax request is done and has filled in its results

Upvotes: 2

Views: 2338

Answers (5)

Tosen
Tosen

Reputation: 176

You can use .off() to remove event handlers.

var attachEvent = function(){

    $(window).scroll(function() {

        $(window).off("scroll");
        $.ajax("example.php").done(function() { 

            //If you want to reattach event
            attachEvent(); 
        });            
    });
};

attachEvent(); 

Upvotes: 0

user235273
user235273

Reputation:

Just use a variable to mark whether an outstanding ajax request is present. If so do not make another request. Else fetch the data. My thinking is that let the user scroll, why to block the UI. In that case it is like making a synchronous call.

var isLoading = false;
//event handler
$(window).scroll(function () {
   // check height..
   // make an ajax request if isLoading is false
   if (!isLoading) {
       $.ajax(/* .. */, success: function () {
           isLoading = false;
       }, 
       error: function () {
           isLoading = false;
       });
       isLoading = true;
   }
}

If you still want to stop listening to event until the ajax response, simply remove the binding in and reattach it in the ajax response handler.

var isLoading = false;
addScrollEvent();

function scrollHandler(e) {
   // check height..
   // make an ajax request if isLoading is false
   if (!isLoading) {
       $.ajax(/* .. */, success: function () {
           isLoading = false;
           addScrollEvent();
       }, 
       error: function () {
           isLoading = false;
           addScrollEvent();
       });
       $(window).off('scroll', scrollHandler);
   }
}

function addScrollEvent() {
    $(window).on('scroll', scrollHandler);
}

Upvotes: 0

Roonaan
Roonaan

Reputation: 1066

Not an answer as such, but a note that doesn't fit well in a comment.

For IE6/IE7/IE8 the .scroll doesn't really perform well and will call your callback dozens (if not hundreds) of times in each scroll. In our projects we use a wrapper function called .detachedScroll to prevent this behavior:

/**
* Detached scroll prevents freezing in IE<=8
*/
if($.browser.msie && parseInt($.browser.version, 10) <= 8) {
    $.fn.scrollDetached = function(callback) {
        return $(this).each(function() {
            var oThis = this;
            clearInterval(this.detachedScrollInterval);
            this.detachedScrollInterval = setInterval(function() {
                if (oThis.hasScrolled) {
                    oThis.hasScrolled = false;
                    // Calling detached scrolling callback
                    callback();
                }
            }, 500);
            $(this).scroll(function() {
                // There was a scrolling event
                oThis.hasScrolled = true;
            });
        });
    };
} else {
    $.fn.scrollDetached = $.fn.scroll;
}

Upvotes: 0

gilly3
gilly3

Reputation: 91467

Before making the AJAX request, unbind the scroll handler. After you've processed the AJAX response, rebind the scroll handler. You'll want to give the scroll handler a name to enable unbinding and rebinding:

$(window).scroll(function scrollHandler() {
    if($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
        $(window).off("scroll", scrollHandler);
        $.ajax({
            ...
            complete: function() {
                $(window).scroll(scrollHandler);
            }
        });
    }
});

Upvotes: 1

Halcyon
Halcyon

Reputation: 57709

Something like this:

var request_pending = false;

function at_bottom_of_page() {
    return $(window).scrollTop() + $(window).height() > $(document).height() - 100;
}

$(window).scroll(function() {
    if (request_pending) {
        return;
    }               
    if (at_bottom_of_page()) {
        request_pending = true;
        doAjax(function (moar_news) {
            render_news(moar_news);
            request_pending = false;
        });
    }
});

Upvotes: 3

Related Questions