Search code examples
jqueryclickjquery-effects

jQuery: do not add more clicks


I hope to explain myself properly.
We have something like this (a simple example):

$('#click').click(function() {
    $('#a').animate({width: 'toggle'}, 1500);
    $('#b').animate({width: 'toggle'}, 1500);
    $('#b').animate({width: 'toggle'}, 1500);
});

Now, if I click several times on "#click", even before the effects are finished, my repeated clicks are added together and the function executed multiple times (it's a really unpleasant thing especially when using "hover", as you know).

But I would like that clicks are detected only if effects are finished. How can I do?

I read the documentation about queue, but I'm not sure that will work in this case.
Can I have some examples?

Thank you.


Solution

  • You're on the right track with queue, just check the length of the queue, e.g.:

    var a = $("#a");
    if (a.queue().length === 0) {
        a.animate(...);
    }
    

    Live Example | Live Source

    You can create a tiny plug-in for this, if you like:

    (function($) {
        $.fn.maybeAnimate = maybeAnimate;
        function maybeAnimate() {
            var args = arguments;
            this.each(function() {
                var $this = $(this);
                if ($this.queue().length === 0) {
                    $this.animate.apply($this, args);
                }
            });
            return this;
        }
    })(jQuery);
    

    ...and then use it like this:

    $("#a").maybeAnimate({width: 'toggle'}, 1500);
    $("#b").maybeAnimate({width: 'toggle'}, 1500);
    $("#b").maybeAnimate({width: 'toggle'}, 1500); // Really #b again???
    

    Live Example | Live Source


    Re your comment below:

    But what to do when the function of the click is more complex and includes not only "animated", but different functions and also if/else? I wish that all the function of the click is a queue. Is it possible?

    For combining the results of animations with other asynchronous things, you'd probably want to use Deferred and Promise objects. You can get the Promise for an animation from the jQuery set using .promise; e.g.:

     var p = $("#a").animate(/*...*/).promise();
    

    You can then combine that promise with other promises/deferreds via $.when and Promise#then.