0

(I really didn't know how to title this, feel free to suggest an edit)

Consider the following sample html:

<div class="grid">
    <div class="item"><span class="icon"></span></div>
    <div class="item"><span class="icon"></span></div>
    <div class="item"><span class="icon"></span></div>
    <div class="item"><span class="icon"></span></div>
    <div class="item"><span class="icon"></span></div>
</div>

Attached to each .icon is some jQuery:

<script type="text/javascript">
    jQuery('.icon').click(function(){
        runAjaxStuff();
        displayNewContent();
    })
</script>

In a nutshell, each time a user clicks an .icon, the corresponding parent .item will perform an AJAX request and finish by displaying additional .item content on the page.

If a user, in this scenario, were to click each of the .item quickly in succession, the AJAX request from a preceeding click is likely to still be waiting for a response. Of course, the new content is also not displayed yet; however, after a handful of seconds and all the requests have had a chance to complete, the user is then barraged with tons of new content being displayed all at once.

What I am after is a method to simply stop execution of any previous click bindings if an .icon is clicked so that only the most recent click ultimately completes.

I am aware that I can make my AJAX call syncronous instead, but I am hoping for a better way that will not seize the user's browser. My jQuery is good enough to get by, but this is something a little more in-depth than I'm used to.

2 Answers 2

3

You got two choices

You can cancel the previous Ajax calls that are open

var xhr = null;
jQuery('.icon').click(function () {
    if (xhr &&  && xhr.readystate != 4) {
        xhr.abort();
    }
    runAjaxStuff();
    displayNewContent();
});

and in your ajax call you would store the call to the

xhr = $.ajax({
    url: 'ajax/progress.ftl',
    success: function(data) {
        //do something
    }
});

or

You can set a "active" flag and not make calls until the last one is complete

var isActive = false;
jQuery('.icon').click(function () {
    if (isActive) {
        return;
    }
    isActive = true;
    runAjaxStuff();
    displayNewContent();
});

and in the success/error/done function

isActive = false;

And you probably want to give the user some notification that either the call is active or that the last call was cancelled just so they know what is happening. Give them a good UX so they do not randomly click.

5
  • +1 Because prevention is always the best way. But if the OP prefers to abort the previous AJAX call - as he specified to perform the most recent click - he may want to check this too: stackoverflow.com/a/446626/2600397 Commented Dec 12, 2013 at 15:13
  • I'd definitely prefer stop/abort, simply because instead of restricting the user, it lets the user do what he wants and deals with it.
    – Kevin B
    Commented Dec 12, 2013 at 15:18
  • Keep in mind that there is not simply AJAX to stop, but possibly animation as well (inside displayNewContent). Will each need to be explicitly stopped individually?
    – pspahn
    Commented Dec 12, 2013 at 15:21
  • Well depending of what you want to accomplish, you should stop everything that's moving. I strongly suggest you to go for the "prevention" way. Commented Dec 12, 2013 at 15:23
  • 1
    You can add a common class and call stop() or do it the first way and not make a request until everything is done. Up to you. Commented Dec 12, 2013 at 15:23
0

First you have to unbind click:

<script type="text/javascript">
    jQuery('.icon').click(function(){
        $('.icon').unbind('click');  // unbind click
        runAjaxStuff();
        displayNewContent();
    })
</script>

Then bind it again in complete event that has $.ajax method:

complete: function() {
    $('.icon').bind('click'); // will fire either on success or error
}

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