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...
Click here for a demo
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...