0

I am trying to learn how to use the .queue() JQuery method. So I started with a basic animation using only setTimeout. I have the code here:

http://jsfiddle.net/2gJQS/8/

I am wondering how to achieve this same animation using queues. The reason for this is I want to be able to add a 'cancel' button to the page that would completely cancel all future steps. Right now if you press the Start button several times quickly, the setTimeout's pile on each other and make it look strange.

I tried listing each animation separately in something like:

$('#target').queue(function(){
    $(this).delay(1000).fadeIn(1000);
    $(this).dequeue();
});

But only the fadeIns and fadeOuts happened at the right time, and not the color and text changes. So I added setTimeout's inside the queue functions for the color and text changes, and this made the timing work. But then when I called

$('#target').clearQueue();

it only stopped the fadeIns and fadeOuts, while the color and text changes still happened.

To summarize my question:

  1. How can I achieve the animation in the link while also having a cancel button that will completely clear all future steps if pressed?

  2. If the answer to 1 is to use queue(), then how do I do this correctly (in light of my failed attempts described above)?

Thanks!

gmath
  • 71
  • 6
  • `delay(ms)` is actually a function. – adeneo Sep 02 '12 at 16:43
  • Right, I forgot that part when I posted the question. I used them in the attempts I described, which were successful for the fadeIns and fadeOuts, only the color and text changes were't timing correctly. – gmath Sep 02 '12 at 16:57
  • $(this).dequeue is a function, so you should be using `$(this).dequeue()`, but instead of that, you should be calling the callback passed to the handler you give to the `queue()` function; for more info see the documentation for `queue()` [here](http://api.jquery.com/queue/). I wrote a [blog post](http://www.mattlunn.me.uk/blog/2012/06/jquery-delay-not-working-for-you/) on this a while ago which explains `queue()` in a different way, if you find it useful. – Matt Sep 02 '12 at 16:59
  • I think using Altinak's second solution is the most elegant. This is what I was going for: http://jsfiddle.net/AYMY7/3/ – gmath Sep 02 '12 at 18:30
  • A useful link : http://stackoverflow.com/questions/1058158/can-somebody-explain-jquery-queue-to-me – Rafael Adel Sep 02 '12 at 19:42
  • @gmath don't forget that all of those `$('#target')` calls can be chained... – Alnitak Sep 02 '12 at 20:59

2 Answers2

2

Functions like .html() and .css() don't use the animation queue, so you should use .queue() to schedule those calls in between other animations, and then use .stop(true, true) to cancel the queue if the start button is pressed again.

Absolutely do not mix setTimeout with jQuery animations - it won't work reliably.

See http://jsfiddle.net/alnitak/EKNAd/ for your fiddle corrected to use jQuery animation queues:

$('#target').stop(true, true)
    .html("This is one.")
    .css('color', '#000000')
  .fadeIn(1000).fadeOut(2000).queue(function() {
    $(this).html("This is two.").css('color', '#dc0000');
    $(this).dequeue();
}).fadeIn(1000).fadeOut(2000).queue(function() {
    $(this).html("This is three").css('color', '#990099');
    $(this).dequeue();
}).fadeIn(1000).fadeOut(2000);

Also, I previously posted this function to allow calling any jQuery function as if it were queued:

(function($) {
    $.fn.queued = function() {
        var self = this;
        var func = arguments[0];
        var args = [].slice.call(arguments, 1);
        return this.queue(function() {
            $.fn[func].apply(self, args).dequeue();
        });
    }
}(jQuery));

See http://jsfiddle.net/alnitak/AYMY7/ for your function rewritten to use this:

$('#target')
    .stop(true, true)
    .html('This is one')
    .css('color', '#000000')
    .fadeIn(1000)
    .fadeOut(2000)
    .queued('html', 'This is two')
    .queued('css', 'color', '#dc0000')
    .fadeIn(1000)
    .fadeOut(2000)
    .queued('html', 'This is three')
    .queued('css', 'color', '#990099')
    .fadeIn(1000)
    .fadeOut(2000);
Community
  • 1
  • 1
Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • animations uses an `fx` queue on elements so its all the same. I agree that if all you're using is jQuery animations, there is no reason to modify the queue – nickaknudson Sep 02 '12 at 17:03
  • Both of these are working awesomely. This is exactly what I was looking for. Thank you. – gmath Sep 02 '12 at 17:30
  • @user1641118 NB: strictly speaking there's no need to queue the very first `html` and `css` calls because they're _supposed_ to happen immediately. It's only the later ones that really need to be queued. I've just updated the examples to show that. – Alnitak Sep 02 '12 at 17:33
  • @Alnitak That makes sense. This has been really helpful. – gmath Sep 02 '12 at 17:37
1

Maybe something like this : here

HTML :

<div id="holder">
<div id="target" style="display:none"></div>
</div>

<button id="start">Start</button>
<button id="cancel">Cancel</button>

script :

$(function(){   
    $('#start').click(function(){
        $(this).attr("disabled", "true");
        $("#target").html("This is one.").fadeIn(1000, function(){
            $(this).fadeOut(1000, function(){
                $(this).html("This is two.").css("color","#dc0000").fadeIn(1000, function(){
                    $(this).fadeOut(1000, function(){
                        $(this).html("This is three.").css("color","#990099").fadeIn(1000, function(){
                            $(this).fadeOut(1000, function(){
                                $(this).css("color","#000000");
                                $("#start").removeAttr("disabled");
                            });
                        });
                    });
                });
            });
        });                 
    });

    $("#cancel").click(function(){
        $("#target").stop().empty();
        $("#start").removeAttr("disabled");

    });
});
Rafael Adel
  • 7,673
  • 25
  • 77
  • 118
  • _you are in a maze of twisty little callbacks, all alike..._ – Alnitak Sep 02 '12 at 17:15
  • Your cancel button does stop the animation, but it if you press Start again right away then there are still leftovers from the previous run that are messing with the display of the current run. – gmath Sep 02 '12 at 17:15
  • @user1641118 Hmmm, could you clarify more ? the `start` button gets disabled as soon as the animation begins, and enabled again when it's finished. – Rafael Adel Sep 02 '12 at 17:20
  • Yeah, sorry I'm not being very clear. What I mean is that if you press start, then wait until it says "This is two." (which is in red) and press cancel, then press start again immediately, then what happens is that "This is one." appears in red still and not in black, which is what it is supposed to be. – gmath Sep 02 '12 at 17:27
  • @user1641118 if "one" is supposed to appear in black, then that should be done at the _start_ of the chain, and not rely on it being reverted back to black at the _end_ of the chain. – Alnitak Sep 02 '12 at 17:30
  • 1
    @Alnitak You're right. I think I fixed that and added a cancel button using your first suggestion here: http://jsfiddle.net/EKNAd/4/ – gmath Sep 02 '12 at 17:34