views:

274

answers:

2

Let's say that I have several animations running at once, and I want to call a function once all of them are finished.

With only one animation, it's easy; there's a callback for that. For example :

$(".myclass").fadeOut(slow,mycallback);

Trouble is, if my selector finds several items, the callback will be called for each of them.

A workaround is not too hard; for example :

<!DOCTYPE html>
<html>
<head>
  <title>Example</title>
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"&gt;&lt;/script&gt;
  <script type="text/javascript">
    $(document).ready(function() {
      var $mc=$(".myclass"),l=$mc.length;
      $mc.fadeOut("slow",function(){
        if (! --l) $("#target").append("<p>All done.</p>");
      });
    });
  </script>
  <style type="text/css">
  </style>
</head>
<body>
  <p class="myclass">Paragraph</p>
  <p class="myclass">Paragraph</p>
  <p class="myclass">Paragraph</p>
  <p class="myclass">Paragraph</p>
  <p class="myclass">Paragraph</p>
  <p class="myclass">Paragraph</p>
  <div id="target"></div>
</body>
</html>

My question is : is there a better way to do this ?

+6  A: 

You can run the same callback for all of them, but only execute the if clause if none are currently being animated anymore, like this:

  $(".myclass").fadeOut("slow", function() {
    if ($(".myclass:animated").length === 0)
      $("#target").append("<p>All done.</p>");
  });

This just checks if any are still being animated via the :animated selector. If you were animating lots of different things then use the same concept, just add to the selector like this:

$(".myclass:animated, .myClass2:animated")

If you're using it in lots of places, I'd make that callback a onFinish function or something to tidy it up.

Nick Craver
Nice, I like the definative aspect of this.
Mark Schultheiss
I like this too, +1
David V.
Ran into this problem too. Clever solution.
George Edison
I've tried this, but the :animated selector doesn't seem to have cleared at the moment the callback is fired. Adding .not(this) before .length make it work.
grahamparks
@grahamparks - It won't be clear *if* there's another animation queued on the element, remember this is just the callback for *this* animation, another may be after it...this script was really written for the context of the question :)
Nick Craver
Nick: Other animations aren't the problem. In my testing, the element still matches *:animated at the moment its own callback is called. Thus length is never 0.
grahamparks
A: 

In my case I have to define

if ($(".myclass:animated").length === 1)
Stefan Frömken