views:

43

answers:

3

Hello,

Is there a way to wait for hide function in a loop? I mean if I have this structure in html:

<div class='example'>
    <span> One </span>
    <span> Two </span>
    <span> Three </span>
<div>

And in js I want to do something like this:

$('.example span').each(function(i, span) {
    $(span).hide('slow');
});

I believe js is asynchronous so it will not wait for hide to end, but maybe there is a way which I don't know to wait until hide animation finishes and continue on next element?

+5  A: 

You can use .delay() to run them at the right times, like this:

$('.example span').each(function(i, span) {
  $(span).delay(600 * i).hide('slow');
});

You can give it a try here

All we're doing here is delaying the next animation 600ms (the "slow" duration) times it's index, so the first starts instantly (0-based, 0*600=0), the second at 600ms (the first should finish then), the third at 1200ms, etc.

Nick Craver
who is **i** here? why it autoincrements?
Syom
@Syom - `i` comes from the callback function provided to the `.each()`, it's the first argument, and it's the index of the item in the array `.each()` is iterating through...so for our purposes, yes, auto-incrementing :)
Nick Craver
understanded. Thanks;)
Syom
+1  A: 

You can call a function when hiding animation is complete - hide the next one from that callback.

function hideTags()
{
  var tags = $('.post-taglist a');
  var len = tags.length;
  var hide = function(i){
    if(i >= len)
      return;
    tags.eq(i).hide(1000, function(){hide(i + 1);});
  };
  hide(0);
}

Run this from your Firebug console to see your tags disappearing one after another.

Amarghosh
You're calling 2 different methods ;) Also you should use `$('.post-taglist a').eq(i)` rather than creating, throwing away and re-creating a new object, for that matter I'd cache the result set once and get your `.length` property off it as well.
Nick Craver
@Nick updated - cached the result set; but now there are three functions in all. /disclaimer: am not a seasoned jQuery programmer.
Amarghosh
@Amarghosh - Oh by two functions I meant the `hideTag` and `hideSpan` inconsistency :) What you have is much improved...one note though, you don't need to check the length and return. `.eq()` will just find no elements and the chain won't execute :)
Nick Craver
@Nick Oh.. that was a typo due to copy pasting between SO page and the firebug console. I thought `eq` will throw index-out-of-bounds or something like that - Firebug tells me it just returns an empty jQuery object; is it correct to assume that hide() method won't be invoked on that object (what would it hide anyway - but I'm more concerned about the code running forever in the background)?
Amarghosh
A: 

I use the async.js library for managing this sort of stuff:

async.forEachSeries($('.example span'), function(span, callback) {
  $(span).hide('slow', callback);
});​

This will run each hide function in series, without relying on a delay function which has to match the speed of the hide animation.

You can try it out here.

Admittedly, it might not be worth including another library just for this one issue, but if you run into problems ordering asynchronous calls such as animations and ajax functions a lot then I recommend you take a look :)

You can find the async.js library on github

Caolan