AngularJS with Animation and Callback

What is the problem

When we use AngularJS, manipulating the DOM element is something we often want to do. I encountered a problem recently that I have an object bound to a bunch of fields in a container, then what I need to do is to bind a new object, but with an fade in and fade out animation. So it is pretty much like this:

  1. Fade out the container with old object
  2. Bind the new object
  3. Fade in the container with new object

How did I solve it

I first went to Google (of course this is what you guys would do as well), and found this article AngularJS - Animating the Angular Way by EggHead. It is a really good tutorial talks about how to define a directive to watch for the attribute and then use the $animate service to do the animation. However, this article did not address how to solve the problem of updating the scope after the animation. So here I just want to quickly give you the way of how to do it.

Actually it is pretty simple, all you need is to add a call back function, and some tricks.

Here is an example, or you can try to open the demo here.

<!DOCTYPE html>
    <title>AngularJS Animate And Callback Demo ::</title>

<div id="ng-app" ng-app="myApp" ng-controller="myController" ng-init="init()">
    <div fade-me="isFade" ng-click="flip()">
        Click this: {{myValue}}

<script src="//"></script>
<script src="//"></script>
<script src="//"></script>

    var myApp = angular.module('myApp', ['ngAnimate']);

    myApp.controller('myController', ['$scope', function($scope) {

        $scope.init = function() {

            // init values
            $scope.isFade = false;
            $scope.myValue = "Foo";


        $scope.flip = function() {

            // flip the value only when the container is faded out
            if ($scope.isFade)
                $scope.myValue = ($scope.myValue === "Foo") ? "Bar" : "Foo";

            // flip the fade value
            $scope.isFade = !$scope.isFade;



    // define the directive
    myApp.directive("fadeMe", ['$animate', function($animate) {
        return function(scope, element, attrs) {

            // watch the fade-me directive
            scope.$watch(attrs.fadeMe, function(newVal) {
                if (newVal) {

                    $animate.addClass(element, "fade", function() {

                        // this its the call back, wrap it in $apply to update the angular models


                } else {
                    $animate.removeClass(element, "fade");

    // define the animate service
    myApp.animation(".fade", function() {
        return {
            addClass: function(element, className, callback) {
                element.animate({ opacity: 0 }, callback);
            removeClass: function(element, className, callback) {
                element.animate({ opacity: 1 }, callback);



Wrap it up

  1. Import necessary scripts (jQuery for animate(), angularjs, angularjs-animate).
  2. Create the directive and define the animate service.
  3. Watch the fade value in the directive and provide a callback with $apply to update the angular model.

The key idea here is to use scope.$apply to update the angular models, because I think the callback is just passed to jQuery as a normal callback function, and has nothing to do with angular. It is about the same issue when you want to use a jQuery plugin.