3

jQuery queue's are very annoying - I can't get my head around it...

The following function contains 4 animations which I want to happen one after the other (not at the same time).

function startupAnime() {

    $("#header").animate({"opacity":"1"},{duration:3000, queue:"global"});
    $("#header").animate({"top":"0px"},{duration:3000, queue:"global"});
    &("#loader").animate({"opacity":"0"},{duration:3000, queue:"global"});
    $("#background").animate({"background-position" : "300px center"},{duration:3000, queue:"global"});
}

$(window).load(function() { 

    startupAnime();
})

The two #header elements will animate one after the other, but the rest all happen at the same time.

I then found out the Queue only works if your animating the same element!! That's not very useful... But adding queue:"name" apparently is supposed to link them into the same queue... although this just stops them from working for me.

Am I missing something here? I'm not sure if queue means 'next animation will start when current one is finished', or 'these animations are being held in a queue waiting for you to release them' by maybe calling queue("global") or something!?

Most suggestions talk about animating one element, or setting up many functions and using callback to 'iterate' through the functions - not very clean if you ask me. I simply want to be able to run a list of animations whenever I ask for it.

NB: A 'list' of animations might animate elements one at a time, but I also might want two or more elements to animate at the same time at some point in the list. Here's a sample:

animate element A
-> then ->
animate element B
-> then ->
animate element C and D together
-> then ->
animate element E
Patrick Keane
  • 663
  • 3
  • 19
  • 41
  • 1
    Use the complete callback of the second #header animation to start the 3rd. It isn't clean by your definition, but neither is using a custom queue or deferred objects which are the alternatives. – Kevin B Aug 28 '13 at 22:04
  • possible duplicate of [How can I animate multiple elements sequentially using jQuery?](http://stackoverflow.com/questions/1218152/how-can-i-animate-multiple-elements-sequentially-using-jquery) – Chris Moschini Oct 19 '14 at 09:05

3 Answers3

10

You have a lot of options, but here is what I would do (because I like the self-explanatory syntax):

$.when(
    $("#header").animate({opacity: 1}, 3000).promise(),
    $("#header").animate({top: 0}, 3000).promise()
).done(function() {
    $("#loader").animate({opacity: 0}, 3000).promise()
    .done(function() {
        $("#background").animate({"background-position" : "300px center"}, 3000)
    })
})

Demo: http://jsfiddle.net/vjazX/

David Hellsing
  • 106,495
  • 44
  • 176
  • 212
3

You have a few options.

Delay it:

$("#loader").delay(6000).animate({"opacity":"0"},{duration:3000});
$("#background").delay(9000).animate({"background-position" : "300px center"},{duration:3000});

Use callbacks:

function startupAnime() {

    $("#header").animate({"opacity":"1"},3000);
    $("#header").animate({"top":"0px"},3000,function(){
        $("#loader").animate({"opacity":"0"},3000,function(){
            $("#background").animate({"background-position" : "300px center"},3000);
        });
    });   

}

or use deferred objects:

function startupAnime() {

    $("#header").animate({"opacity":"1"},3000);
    $("#header").animate({"top":"0px"},3000).promise().done(function(){
        $("#loader").animate({"opacity":"0"},3000).promise().done(function(){
            $("#background").animate({"background-position" : "300px center"},3000);
        });
    });   

}

Another deferred object option:

function startupAnime() {

    $("#header").animate({"opacity":"1"},3000);
    $("#header").animate({"top":"0px"},3000).promise().then(function(){
        return $("#loader").animate({"opacity":"0"},3000).promise();
    }).done(function(){
        $("#background").animate({"background-position" : "300px center"},3000);
    });

}  

I won't even post the custom queueing because that just gets ridiculous.

None of them are really very clean. Pick your poison. The .delay() looks the cleanest to me, but may be less maintainable. Though the alternatives aren't that maintainable either.

If i had to, I would use the 2nd deferred object sample because i don't feel comfortable with the delay and hate the pyramid of doom.

Kevin B
  • 94,570
  • 16
  • 163
  • 180
  • `delay` looks cleaner, but callbacks are more reliable. You can clean up some code by using another syntax: `$("#header").animate({top:0}, 3000, function() { ...`. – David Hellsing Aug 28 '13 at 22:14
  • @David callbacks are nice, but what about if you have conditional animations (e.g. calling animations on an object with a `.not()` caveat) but still want to ensure subsequent animations are executed? if they are in the callback and the `.not()` applies they won't be - been trying to wrap my head around this... is that what promises are for? – Ennui Jun 27 '14 at 13:14
  • I don't quite understand the scenario you just described – Kevin B Jun 27 '14 at 13:33
0

Try using jQuery promise API. You can pull the promise from each jQuery element and then attach a done callback to it.

For example,

$("#header").animate({"opacity":"1"},{duration:3000 }).promise().done(function () {
    $("#header").animate({ "top":"0px" },{ duration:3000 });
});

You can refer to jQuery's promise API for more information. http://api.jquery.com/promise/

Tmax6
  • 41
  • 3