JavaScript Animations in AngularJS Applications

Ravi
Share

AngularJS is a feature-rich framework for creating single-page web applications, bringing all capabilities that one needs for building rich and interactive apps. One of the key features that Angular brings is the support of animations.

We can animate a portion of the application to indicate a change occurring. In my last article I covered the support of CSS animations in Angular applications. In this article, we will see how to leverage JavaScript to animate the AngularJS apps.

In Angular, the only difference between CSS and JavaScript animations is their definition. There is no difference in the way the defined animations are used. To start with, we need to load the ngAnimate module to the root module of our application.

angular.module('coursesApp', ['ngAnimate']);

The animation events to be handled in the JavaScript animation also remain the same. Following is a list of directives supporting animations and their events for different actions:

Directives Events
ng-view
ng-include
ng-switch
ng-if
enter
leave
ng-repeat enter
leave
move
ng-show
ng-hide
ng-class
add
remove

The above listing is the same as the one in the previous article, but doesn’t mention the corresponding CSS classes, as we don’t need them to define JavaScript animations. These events are generated only if the application module loads the ngAnimate module. Now let us see how to animate some of the directives.

Syntax for a Custom Angular Animation

A basic skeleton of a custom JavaScript animation is as follows:

angular.module('coursesApp').animation('.name-of-animation', function(<injectables>) {
  return {
    event: function(elem, done){
      //logic of animation
      done();
    }
  };
});

Here are some things to keep in mind when writing a JavaScript animation in AngularJS:

  1. The name of the animation starts with a dot(.)
  2. Every animation action accepts two parameters:
    • An object that is the current DOM element on which the animation will be applied. It is either a jQlite object if jQuery is not loaded before loading AngularJS. Otherwise, it is a jQuery object.
    • A callback function that is called once the animation is complete. Action of the directive is halted till the done function is called.

We have a number of JavaScript libraries like jQuery, Greensock, Anima and several others that ease the work of writing animations. To keep things simple, I’m using jQuery for creating animations in this article. To learn about the other libraries, you can visit their respective sites.

Animating ng-view

The animation applied on an ng-view directive takes place when a user switches between views of an AngularJS application. As listed in the table above, we can animate when a view enters or leaves. It is not necessary to handle both of these cases; we can animate the one that seems necessary.

Following is an animation that induces some visual effect when a view is entering:

courseAppAnimations.animation('.view-slide-in', function () {
  return {
    enter: function(element, done) {
      element.css({
        opacity: 0.5,
        position: "relative",
        top: "10px",
        left: "20px"
      })
      .animate({
        top: 0,
        left: 0,
        opacity: 1
        }, 1000, done);
    }
  };
});

The above creates a slide-in effect when a view enters the page. The done method is passed as the callback. This is to indicate that the animation is complete and now the framework can continue with the next action.

Notice the way the animate() method is called. We didn’t have to convert the element to a jQuery object as the jQuery library is loaded before loading AngularJS.

Now we need to apply this animation to the ng-view directive. Though the animation is defined in JavaScript, by convention we apply it using a class on the target directive.

<div ng-view class="view-slide-in"></div>

Animating ng-repeat

ng-repeat is one of the most important directives, with a number of options available. Two of the basic operations of the directive are filtering and sorting. Items under the directive are added, removed, or moved, depending on the kind of action performed.

Let’s apply some basic animations so that one can see when a change is happening.

courseAppAnimations.animation('.repeat-animation', function () {
  return {
    enter : function(element, done) {
      console.log("entering...");
      var width = element.width();
      element.css({
        position: 'relative',
        left: -10,
        opacity: 0
      });
      element.animate({
        left: 0,
        opacity: 1
      }, done);
    },
    leave : function(element, done) {
      element.css({
        position: 'relative',
        left: 0,
        opacity: 1
      });
      element.animate({
        left: -10,
        opacity: 0
      }, done);
    },
    move : function(element, done) {
      element.css({
        left: "2px",
        opacity: 0.5
      });
      element.animate({
        left: "0px",
        opacity: 1
      }, done);
    }
  };
});

Animating ng-hide

The ng-hide directive adds or removes the ng-hide CSS class on the target element. To apply an animation, we need to handle the cases of adding and removing the CSS class. The name of the class is passed to the animation handler class. This lets us inspect the class and take appropriate action.

Below is an example of animation code that fades out or fades in the element on activation or deactivation of the ng-hide directive:

courseAppAnimations.animation('.hide-animation', function () {
  return {
    beforeAddClass : function(element, className, done) {
      if (className === 'ng-hide') {
        element.animate({
          opacity: 0
        },500, done);
      } else {
        done();
      }
    },
    removeClass : function(element, className, done) {
      if (className === 'ng-hide') {
      element.css('opacity',0);
      element.animate({
          opacity: 1
        }, 500, done);
      } else {
        done();
      }
    }
  };
});

Animating a Custom Directive

To animate a custom directive, we need to use the $animate service. Though $animate is part of the AngularJS core framework, ngAnimate should be loaded to make best use of the service.

Using the same demo as the last article, we’re presenting a page with a list of courses. We create a directive to show details of a course in a box, and the contents of the box would change after clicking the “View Statistics” link. Let’s add an animation to make the transition visible to the user.

We’ll add a CSS class when the transition happens and we’ll remove the class once the animation is complete. Below is the code for this directive:

app.directive('courseDetails', function ($animate) {
      return {
        scope: true,
        templateUrl: 'courseDetails.html',
        link: function (scope, elem, attrs) {
          scope.viewDetails = true;
          elem.find('button').bind('click', function () {
            $animate.addClass(elem, "switching", function () {
              elem.removeClass("switching");
              scope.viewDetails =! scope.viewDetails;
              scope.$apply();
        });
      });
    }
  };
});

As you can see, we are performing the action after the animation is completed. On inspecting the directive element in the browser developer tools, we will see the classes switching-active and switching-add being added and removed very quickly. We can define either a CSS transition or a custom JavaScript animation to see the animation happening. Following is a sample CSS transition that can be used with the above directive, vendor prefixes omitted for brevity:

.det-anim.switching {
  transition: all 1s linear;
  position: relative;
  opacity: 0.5;
  left: -20px;
}

Alternatively, here is a jQuery animation to use for the same directive:

courseAppAnimations.animation('.js-anim', function () {
  return {
    beforeAddClass: function(element, className, done) {
      if (className === 'switching') {
        element.animate({
          opacity: 0
        },1000, function (){
          element.css({
            opacity: 1
          });
          done();
        });
      }
      else {
        done();
      }
    }
  }
});

One of these animations can be applied on the custom directive just as we applied the animations on the built-in directives.

<div course-details 
     class="det-anim"
     title="{{course.title}}">
</div>

You can see all of the above animations in action on the demo page.

Conclusion

Animations, when used appropriately and functionally, bring life to applications. As we’ve seen, AngularJS has rich support for both CSS and JavaScript animations. You can choose one of these based on your team’s circumstances.

But use of a lot of animations may lead to a slower application and the application may seem over-engineered to an end user. So, this weapon has to be used carefully and optimally.