views:

899

answers:

4

Hi all,

Please forgive me if this is an obvious one.

I have an unknown amount of elements on a page, which I need to loop through one at a time and do stuff to. However, I need the loop to pause until the functions used on the elements have completed, and then continue on to the next iteration.

I tried doing this in a $.each loop, but it fired off the commands far to quickly and finished without waiting for them to complete.

Any ideas?

$('elem').each(function(){
    $(this).fadeIn().wait(5000).fadeOut();
});

This is what I have, very simple. I got the wait() function from here: jquery cookbook site.

Problem is, the loop doesnt wait - the actual command works as intended, it's just that they all go off at once.

Any help appreciated, thanks.

EDIT: After this is executed, I may want to then execute the loop again, so that the list of elems will be faded in / out again in sequence

EDIT2: Have since gotten the 1.4.2 jQuery lib, was using 1.3.2, hence the custom wait() function. Now using delay() as mentioned by lobstrosity. Managed to cobble together something close to what I need from his answer, thanks lobstrosity :) .

A: 

You probably need to call wait before the first function :

  $(this).wait().fadeIn().wait(5000).fadeOut();

The other option is to use the callback.

 $(this).wait().fadeIn('slow', function(){$(this).fadeOut('slow')});

This way the fadeOut does not start until the fadeIn is done.

Vincent Ramdhanie
thanks for the answer, but the order of the fadeIn and fadeOuts isn't an issue, it's the fact that the .each loop calls each one of them inside about 0.3 of a second, and makes it all happen at the same time, I need the loop to wait for the callback.
alan
+2  A: 

Your main loop using each() will run without delay over your collection of elements. You need to queue these elements instead.

This might need tweaking (and could possibly use jQuery queues?) but to demonstrate using recursion to process the queue:

function animate(elems) {
    var elem = elems.shift();
    $(elem).fadeIn().wait(5000).fadeOut(2000, function() {
        if (elems.length) {
            animate(elems);
        }
    });
}

var elems = $('elem');
animate(elems);
Greg K
I think an unknown number of elements is fine for this because we just `shift()` the next elem off the array. This will only run over your collection once though, then terminate.
Greg K
+5  A: 

First of all, jQuery 1.4 added the delay function, which I assume is what your custom wait implementation is doing.

Using delay, you can sort of fake the functionality of each element "waiting" on the previous element to finish by using the first parameter to the each callback as a multiplier for an intial delay. Like this:

var duration = 5000;

$('elem').each(function(n) {
    $(this).delay(n * duration).fadeIn().delay(duration).fadeOut();
});

So the first element will fadeIn immediately. The second will fadeIn after 5,000 ms. The third after 10,000 ms and so on. Keep in mind that this is faking it. Each element is not actually waiting on the previous element to finish.

Lobstrosity
aaaahh this is quite close, thanks. And I was using 1.3.2, just got the latest lib, thanks for pointing that out.The only issue with this one is that once I do the actions to $('.elem'), I may want to do it all again. I'll edit the question to refelct this, should have mentioned it, thanks.
alan
I haven't got it perfect yet, but this answered my question, thanks alot.
alan
A: 

Here's a demo of my solution.

What you need isn't a loop to handle the processing. What you want is to chain the calls. Seems like there might be a simpler way but here's a brute-force method.

// Create a function that does the chaining.
function fadeNext(x,y) {
  return function() { x.fadeIn(100).delay(100).fadeOut(1000, (y?y.fadeNext:y)); };
}

// Get all the elements to fade in reverse order.
var elements = [];
$('.f').each(function(i,e) {elements.unshift(e);});

// Iterate over the elements and configure a fadeNext for each.
var next;
for (var i in elements) {
  var e = $(elements[i]);
  e.fadeNext = fadeNext(e,next);
  next = e;
}

// Start the fade.
next.fadeNext();
nicerobot
this is a good idea, thanks for posting.This code is good :)
alan