Luther Baker Luther Baker - 1 year ago 125
Javascript Question

Invoking a jQuery function after .each() has completed

In jQuery, is it possible to invoke a callback or trigger an event after an invocation of

(or any other type of iterative callback) has completed.

For example, I would like this "fade and remove" to complete

$(parentSelect).nextAll().fadeOut(200, function() {

before doing some calculations and inserting new elements after the
. My calculations are incorrect if the existing elements are still visible to jQuery and sleeping/delaying some arbitrary amount of time (200 for each element) seems like a brittle solution at best.

I can easily
the necessary logic to an event callback but I'm not sure how to cleanly invoke the
after the above iteration has completed. Obviously, I can't invoke the trigger inside the iteration as it would fire multiple times.

In the case of
, I've considered adding something to the end of the data argument (that I'd manually look for in the iteration body) but I'd hate to be forced to that so I was hoping there was some other elegant way to control the flow with respect to iterative callbacks.


An alternative to @tv's answer:

var elems = $(parentSelect).nextAll(), count = elems.length;

elems.each( function(i) {
  $(this).fadeOut(200, function() { 
    if (!--count) doMyThing();

Note that .each() itself is synchronous — the statement that follows the call to .each() will be executed only after the .each() call is complete. However, asynchronous operations started in the .each() iteration will of course continue on in their own way. That's the issue here: the calls to fade the elements are timer-driven animations, and those continue at their own pace.

The solution above, therefore, keeps track of how many elements are being faded. Each call to .fadeOut() gets a completion callback. When the callback notices that it's counted through all of the original elements involved, some subsequent action can be taken with confidence that all of the fading has finished.

This is a four-year-old answer (at this point in 2014). A modern way to do this would probably involve using the Deferred/Promise mechanism, though the above is simple and should work just fine.