Running code after an AngularJS animation has completed

Ed Hinchliffe picture Ed Hinchliffe · Jan 4, 2014 · Viewed 22.2k times · Source

I have an element whose visibility is toggled by ng-show. I'm also using CSS animations - the automatic ones from ng-animate - on this element to animate its entry.

The element will either contain an image or a video.

In the case that the element contains a video, I want to play it, but I don't want to play the video until it's finished animating in.

As such, I was wondering if there's an easy way to bind a callback to the end of a CSS animation in AngularJS?

The docs reference a doneCallback, but I can't see a way to specify it...

One workaround(?) I have thought of is $watching element.hasClass("ng-hide-add-active") and waiting for it to fire with (true, false), implying it's just been removed..

Is there a nicer way?

Answer

Michal Charemza picture Michal Charemza · Jan 4, 2014

As @zeroflagL has suggested, a custom directive to replace ngShow is probably the way to go. You can use & to pass callbacks into the directive, which can be called after the animations have finished. For consistency, the animations are done by adding and removing the ng-hide class, which is the same method used by the usual ngShow directive:

app.directive('myShow', function($animate) {
  return {
    scope: {
      'myShow': '=',
      'afterShow': '&',
      'afterHide': '&'
    },
    link: function(scope, element) {
      scope.$watch('myShow', function(show, oldShow) {
        if (show) {
          $animate.removeClass(element, 'ng-hide', scope.afterShow);
        }
        if (!show) {
          $animate.addClass(element, 'ng-hide', scope.afterHide);
        }
      });
    }
  }
})

Example use of this listening to a scope variable show would be:

<div my-show="show" after-hide="afterHide()" after-show="afterShow()">...</div>

Because this is adding/removing the ng-hide class, the points about animating from the docs about ngShow are still valid, and you need to add display: block !important to the CSS.

You can see an example of this in action at this Plunker.