Jason210
Jason210

Reputation: 3380

jQuery using the .delay() method in an .each() loop

With the following code I want the li elements to fade in one by one, but the all fade in together:

$('li').each(function () {
    $(this).delay(1000).fadeIn(1000);
});

Can anyone explain why they do not fade in one by one?

Upvotes: 0

Views: 3299

Answers (4)

Alnitak
Alnitak

Reputation: 340055

The .delay call doesn't stop the loop from carrying on immediately, so all of the delays and animations will start (pretty much) at once.

The most trivial solution is to stagger the delay by the current index number:

$('li').each(function(index) {
    $(this).delay(1000 * index).fadeIn(1000);
});

A better solution would use a pseudo-recursive loop and the "completion callback" of the animation to trigger the next iteration:

var els = $('li').get();
(function loop() {
    if (els.length) {
        var el = els.shift();
        $(el).fadeIn(1000, loop);
    }
})();

This method is generally preferable because it ensures that the next fade-in cannot possibly start until the previous has finished, and also avoids creating multiple parallel delay / fade queues (one per element) since the 2nd animation isn't queued until the first has finished.

Upvotes: 2

enguerranws
enguerranws

Reputation: 8233

I guess this is because you basically telling each li to wait 1 sec and to fade in. So that's what they do :)

Right now, your code is similar to:

$('li').delay(1000).fadeIn(1000);

Try something like that :

var delay = 0;
$('li').each(function () {
    $(this).delay(delay).fadeIn(1000);
    delay += 1000;
});

Or, as Alnitak suggest, a cleaner way is to use the current index provided by $.each() :

$('li').each(function (index) {
    // index will return the loop index starting to 0
    $(this).delay(index*1000).fadeIn(1000);
});

Upvotes: 1

toomanyredirects
toomanyredirects

Reputation: 2002

This is a misunderstanding of jQuery.each. It doesn't mean do it for one, then wait for that to finish before moving on, for that you'd need to use a promise.

Instead, try changing your delay to a multiple of the index of each LI in the array, e.g.:

$('li').each(function(index) {
  $(this).delay((index + 1) * 1000).fadeIn(1000);
});

Since array indices always start from 0, and 0 * 1000 = 0, I've added 1 to the index before multiplying by 1000 to ensure the first one happens after 1 second, the second after 2 seconds and so on.

If you don't want a 1s delay to the first li fading in, then it's simply:

$('li').each(function(index) {
  $(this).delay(index * 1000).fadeIn(1000);
});

Upvotes: 0

fengd
fengd

Reputation: 7579

cause each is not delayed. Every delay is applied almost at the same time.

you may want to try use the complete part do fadeIn the next element

.fadeIn( [duration ] [, complete ] )

jQuery api doc

Upvotes: 0

Related Questions