Animations & Sequencing
with ngAnimate

By: Matias Niemelä

matias [at] yearofmoo [dot] com
ng-europe 2014

Basics: What is ngAnimate?

ngAnimate enables animations in Angular

Without the need for complex code

To determine when things are triggered

And all structural ng-directives support them...

Getting up and running

The ngAnimate module is included into the app

A CSS class is added to the directive element

The animations are then triggered

And the browser takes over

Using ngAnimate as module

<script type="text/javascript" src="angular.js"></script> <script type="text/javascript" src="angular-animate.js"></script> <script type="text/javascript"> // then use it as a module var ngModule = angular.module('myApp', ['ngAnimate']) </script>

So something like this?

<button ng-click="something=!something"> On / Off </button> <!-- add "zoom" as a CSS class here --> <div ng-if="something">...WHOA...</div>

Transitions & Animations

ngAnimate supports both transitions...

and keyframe animations

Just add the code to the starting CSS class

The corresponding CSS code

.zoom.ng-enter { transition:0.5s linear all; position:relative; left:-200px; opacity:0; } .zoom.ng-enter.ng-enter-active { opacity:1; left:0; }

JavaScript-based animations

ngAnimate also supports using JavaScript for animations

Use ngModule.animation(...)

Then create the animation for the associated event

And then do the animation and call done

The corresponding JS code

ngModule.animation('.fade', function() { return { enter : function(element, done) { element.css({ position: relative, left: '-200px', opacity:0 }); element.animate({ left: '0px', opacity:1 }, done); } } });

Directive Support?

Directive Events
ng-include, ng-view, ng-switch, ng-if enter + leave
ng-message enter + leave
ng-repeat enter + leave + move
ng-class addClass + removeClass
ng-show + ng-hide addClass + removeClass
ng-model + ng-form addClass + removeClass

Example: ng-repeat

<input type="search" ng-model="q" /> <button ng-click="showBooks()">Show</button> <button ng-click="hideBooks()">Hide</button> <hr /> <div ng-repeat="book in books | filter:q" class="repeat-animation"> {{ $index + 1 }}. <strong>{{ book }}</strong> </div>

Example: ng-repeat

Example: ng-repeat stagger

.repeat-animation.ng-enter { transition:0.5s linear all; ... } .repeat-animation.ng-enter.ng-enter-active { ... } .repeat-animation.ng-leave { transition:0.5s linear all; ... } .repeat-animation.ng-leave.ng-leave-active { ... } .repeat-animation.ng-enter-stagger, .repeat-animation.ng-leave-stagger { transition-delay:0.2s; transition-duration:0s; }

Example: ng-repeat stagger

Now what's going on in 1.3?

1.3 fixed a large collection of bugs in ngAnimate

fixes to transitions & keyframe animations

fixes to ngShow/ngHide & staggering

promise-based animations

and new stuff like inline-style hinting

1.3 Fixes to transitions + keyframes

ngAnimate treats transitions naturally now

and doesn't block or cut off the animation

.show-infinite { animation: rotate 1s infinite; -webkit-animation: rotate 1s infinite; }

1.3 fixes to ngShow + ngHide

No more need to set the display property

.show-hide-animation { transition:1s linear all; } .show-hide-animation.ng-hide { opacity:0; }

3rd-Party Stagger

3rd Party Keyframes can be attached to a stagger

.animation.ng-enter { animation:1s slideIn; } .animation.ng-enter-stagger { animation-delay:0.5s; animation-duration:0s; }

Click here for a demo

ngAnimateChildren

Using ng-animate-children="true" to allow parent/child animations

<div ng-animate-children="true"> <div ng-if="on" class="animate-me"> ... <div ng-show="on" class="animate-me"> ... </div> </div> </div>

$animate: Promises

The $animate service now uses promises

$animate.enter(element, parent).then(function() { alert('the animation is done!'); });

$animate: Promises

But we need to call $scope.$apply when changing data

$animate.enter(element, parent).then(function() { $scope.$apply(function() { $scope.title = "cool!"; }); });

$animate: Classes

Calls to $animate.addClass and $animate.removeClass

Are resolved & combined into one animation

$animate.addClass(element, 'one'); $animate.removeClass(element, 'one'); $animate.addClass(element, 'two'); $animate.addClass(element, 'three'); //only two + three continue

$animate: Inline Styling

Directives can now seed styles into animations

$animate.addClass(element, 'my-class', { from: { /* starting styles */ position: 'relative', left: 0 }, to: { /* destination styles */ left: clickCoordinatesX } });

$animate: Inline Styling

transitions and/or keyframes absorb the styles

.animation { transition:5s linear all; animation:1s wave infinite; } @keyframes wave { 0% { transform: translateY(0px); } 25% { transform: translateY(-50px); } 50% { transform: translateY(0px); } 75% { transform: translateY(50px); } 100% { transform: translateY(0px); } }

$animate: Inline Styling

JS Animations will get the styles passed into the code

myModule.animation('.animation', { return { addClass : function(element, className, done, styles) { alert(styles.from); /* starting styles */ alert(styles.to); /* destination styles */ }, removeClass : function(element, className, done, styles) { /* same thing */ } } });

$animate.animate()

$animate.animate() is designed for one time animations

$animate.animate(element, { /* starting styles */ position: 'relative', left: 0 },{ /* destination styles */ left: clickCoordinatesX }, 'super-inline-animation');

$animate.animate()

Then we can use transitions or keyframes like normal

.super-inline-animation { transition: 1s linear all; }

Click here to view this demo

What else is there?

animations are great but...

these are one time animations

so how can we sequence or group together?

Without complicating our HTML/CSS/JS code

How do we sequence things?

When one animation happens

Then another...

Or a group of animations

And then run a parent animation???

This doesn't work too well

/* first leave */ .my-view.ng-leave { transition: 1s linear all; } /* wait for leave to finish */ .my-view.ng-enter { transition: 1s linear all; transition-delay:1s; }

This gets super messy

ngModule.animation('.cool', function($timeout) { var DURATION = 1000; return { leave : function(element, done) { runAnimation(element, DURATION, done); }, enter : function(element, done) { $timeout(function() { runAnimation(element, DURATION, done); }, DURATION, false); } }; });

Template DOM access?

We need to have access to the template

Before it is displayed to the user

And control what components load and when

Not everything uses directives

How do we apply ngAnimate to p, div, table tags

Without using directives or applying $animate directly?

Without complicating our HTML?

ngAnimateLayout

Use this to control the layout...

A simple example

Let's say we had something like this

<button ng-click="visible=true">Show Greeting</button> <div ng-if="visible" class="dark-stage"> <ul> <li>Hi there</li> <li>Welcome to by blog</li> <li>It's great to have you here</li> <li>Please visit often</li> <li>Don't leave :(</li> <li>I'm so lonely</li> </ul> </div>

A simple example

Let's say we had something like this

Let's use ngAnimateLayout

An experimental module

To control how the structural directives render

First include the ngAnimateLayout module

Then attach the animation steps into the HTML

Then API IS NOT FINAL!

Animation Sequence Declarations

<ng-animation> <ng-animate-sequence on="EVENT"> <ng-animate selector="..." stagger="..."></ng-animate> <ng-animate selector="..." stagger="..."></ng-animate> ... <ng-animate selector="..." stagger="..."></ng-animate> </ng-animate-sequence> </ng-animation>

Let's use ngAnimateLayout

<button ng-click="visible=true">Show Greeting</button> <div ng-if="visible" class="dark-stage"> <ng-animation> <ng-animate-sequence on="enter"> <ng-animate selector="li" stagger="500"></ng-animate> </ng-animate-sequence> </ng-animation> <ul> <li>Hi there</li> <li>Welcome to by blog</li> <li>It's great to have you here</li> <li>Please visit often</li> <li>Don't leave :(</li> <li>I'm so lonely</li> </ul> </div>

So what can we do with this?

Click here to view this demo

So what can we do with this?

It all started with Material Design

And the complex requirement of the page transitions

Click here for the full page

So what can we do with ngAnimateLayout

Control when elements enter and leave the template

Apply scope-based data into animations

Transfer elements between templates

Much much more!

What can this lead to?

Better control over how the page renders itself

But more importantly

The sequencer may be a higher level of control

To manage the life-cycle of a view

That's it for now...

Name: Matias Niemelä

Twitter: @yearofmoo

Website: www.yearofmoo.com

Email: matias [at] yearofmoo [dot] com

m
e
r
c
i