@NickSeegmiller
Born and raised in Utah
CS Degree from University of Utah
Married 10 years with 8 year old daughter
Perl web development for Backcountry.com
C/C++ game development for Sensory Sweep
C/Java public safety applications for Spillman Technologies
Angular + Android home automation app development for Vivint
Initial "unstable" support added in 1.1.4 quantum-manipulation (Apr 2013)
Required ng-animate directive that you passed animation classes to
"Proper" support in 1.2.0 timely-delivery (Nov 2013)
Current version we know and love
"Big" changes coming in 1.4
angular.module('angular-examples', ['ngRoute', 'ngAnimate']);
<script src="<cdn-path>/angularjs/1.3.14/angular.js"></script>
<script src="<cdn-path>/angularjs/1.3.14/angular-route.min.js"></script>
<script src="<cdn-path>/angularjs/1.3.14/angular-animate.min.js"></script>
app.js
index.html
enter & leave
<div ng-if="ngif" class="example-block fade-in-out">
<img src="img/plainDoge.jpg">
<h1>ng-if</h1>
</div>
ng-if
<div ng-include="nginclude" class="fade-in-out"></div>
ng-include
<div ng-view class="full-height no-overflow fade-in-out"></div>
ng-view
etc
// Fade in and out done with pure CSS transitions
.fade-in-out.ng-enter, .fade-in-out.ng-leave {
-webkit-transition: 0.5s linear all;
transition: 0.5s linear all;
}
.fade-in-out.ng-enter {
opacity: 0;
}
.fade-in-out.ng-leave {
opacity: 1;
}
.fade-in-out.ng-enter.ng-enter-active {
opacity: 1;
}
.fade-in-out.ng-leave.ng-leave-active {
opacity: 0;
}
$transition-time: .5s;
.opacity-fade {
&.ng-enter {
opacity: 0;
@include transition(opacity $transition-time);
&.ng-enter-active {
opacity: 1;
}
}
&.ng-leave {
opacity: 1;
@include transition(opacity $transition-time);
&.ng-leave-active {
opacity: 0;
}
}
}
@keyframes fade-in {
0% { opacity: 0; }
90% { opacity: .5; }
100% { opacity: 1; }
}
@-webkit-keyframes fade-in {
0% { opacity: 0; }
90% { opacity: .5; }
100% { opacity: 1; }
}
@keyframes fade-out {
0% { opacity: 1; }
90% { opacity: .5; }
100% { opacity: 0; }
}
@-webkit-keyframes fade-out {
0% { opacity: 1; }
90% { opacity: .5; }
100% { opacity: 0; }
}
$transition-time: .5s;
.keyframe-fade-in-out {
&.ng-enter {
-webkit-animation: $transition-time fade-in;
animation: $transition-time fade-in;
}
&.ng-leave {
-webkit-animation: $transition-time fade-out;
animation: $transition-time fade-out;
}
}
Both views are in the DOM at the same time
Consider "position: absolute;"
.opacity-fade-absolute {
&.ng-enter {
opacity: 0;
position: absolute; // Here
@include transition(opacity $transition-time);
&.ng-enter-active {
opacity: 1;
}
}
&.ng-leave {
opacity: 1;
position: absolute; // Here
@include transition(opacity $transition-time);
&.ng-leave-active {
opacity: 0;
}
}
}
$scope.go = function (page, transitionClass) {
if (transitionClass !== undefined) {
$rootScope.transitionClass = transitionClass;
}
$location.path(page);
};
<div class="full-height no-overflow {{transitionClass}}" ng-view></div>
index.html
Controller
<li ng-click="go('/other-page', 'opacity-fade-absolute')">Other Page</li>
View
add & remove
.opacity-fade {
&.ng-show {
opacity: 0;
@include transition(opacity $transition-time);
&.ng-show-active {
opacity: 1;
}
}
&.ng-hide {
opacity: 1;
@include transition(opacity $transition-time);
&.ng-hide-active {
opacity: 0;
}
}
}
This doesn't work!
Toggling ng-hide class
.fade-show {
@include transition(opacity $transition-time);
// Removing hide is showing the element
&.ng-hide-remove {
opacity: 0;
&.ng-hide-remove-active {
opacity: 1;
}
}
// Adding hide is hiding the element
&.ng-hide-add {
opacity: 1;
&.ng-hide-add-active {
opacity: 0;
}
}
}
.ng-hide {
display: none !important;
}
.fade-show {
@include transition(opacity $transition-time);
// Removing hide is showing the element
&.ng-hide-remove {
opacity: 0;
display: block !important; // Here
&.ng-hide-remove-active {
opacity: 1;
}
}
// Adding hide is hiding the element
&.ng-hide-add {
opacity: 1;
display: block !important; // Here
&.ng-hide-add-active {
opacity: 0;
}
}
}
Specifically the GreenSock Animation Platform (GSAP)
http://greensock.com/gsap
<div ng-if="fade-in" class="example-block fade-in-out-js">
<img src="img/plainDoge.jpg">
<h1>fade in/out js</h1>
</div>
View
angular.module(
'angular-examples',
['angular-examples.animations', 'ngRoute', 'ngAnimate']
)
.constant('TweenMax', TweenMax)
app.js
angular.module('angular-examples.animations')
.animation('.fade-in-out-js', ['TweenMax',
function(TweenMax) {
return {
enter: function(element, done) {
// Some sort of animation
},
leave: function(element, done) {
// Some sort of animation
}
}
}
])
;
enter: function(element, done) {
TweenMax.fromTo(
element,
fadeTime,
{opacity: 0},
{opacity: 1, onComplete: done}
);
},
leave: function(element, done) {
TweenMax.to(
element,
fadeTime,
{opacity: 0, onComplete: done}
);
}
Don't forget to call the done function!
show: function(element, done) {
// This is wrong
},
hide: function(element, done) {
// This is wrong
},
add: function(element, done) {
// And this
},
remove: function(element, done) {
// This too
},
ngHideAdd: function(element, done) {
// Nope
},
ngHideRemove: function(element, done) {
// Still nope
},
//animation that can be triggered before the class is added
beforeAddClass: function(element, className, done) { },
//animation that can be triggered after the class is added
addClass: function(element, className, done) { },
//animation that can be triggered before the class is removed
beforeRemoveClass: function(element, className, done) { },
//animation that can be triggered after the class is removed
removeClass: function(element, className, done) { }
removeClass: function(element, className, done) {
if (className === 'ng-hide') {
element.removeClass('ng-hide');
TweenMax.fromTo(
element,
fadeTime,
{opacity: 0},
{opacity: 1, onComplete: done}
);
}
else {
done();
}
},
beforeAddClass: function(element, className, done) {
if (className === 'ng-hide') {
TweenMax.to(
element,
fadeTime,
{opacity: 0, onComplete: done}
);
}
else {
done();
}
}
enter: function(element, done) {
TweenMax.fromTo(
element,
time,
{opacity: 0},
{opacity: 1, onComplete: function() {
TweenMax.fromTo(
element,
time,
{x: 0, rotationZ: 0},
{x: 200, rotationZ: 90, onComplete: function() {
TweenMax.fromTo(
element,
time,
{y: 0},
{y: 200, onComplete: done}
);
}}
)
}});
},
enter: function(element, done) {
TweenMax.fromTo(
element,
time,
{
x: 0, y: 0,
scaleX: 1, scaleY: 1,
skewX: 0, skewY: 0,
rotationZ: 0, rotationY: 0
},
{
x: 200, y: 300,
scaleX: 2, scaleY: 3,
skewX: "5deg", skewY: "10deg",
rotationY: 45, rotationZ: 30,
onComplete: done
}
);
},
<!-- mix css & js -->
<div ng-if="mixed" class="example-block mixed">
<img src="img/plainDoge.jpg">
<h1>mixed</h1>
</div>
.mixed {
&.ng-enter {
opacity: 0;
@include transition(opacity $transition-time);
&.ng-enter-active {
opacity: 1;
}
}
&.ng-leave {
opacity: 1;
@include transition(opacity $transition-time);
&.ng-leave-active {
opacity: 0;
}
}
}
.animation('.mixed', ['TweenMax',
function(TweenMax) {
var transitionTime = 0.5;
return {
enter: function(element, done) {
TweenMax.fromTo(
element,
transitionTime,
{scale: 1, x: 0, y: 0},
{scale: 2, x: element.width(), y: element.height(),
onComplete: done}
);
},
leave: function(element, done) {
TweenMax.to(
element,
transitionTime,
{scale: 1, x: 0, y: 0, onComplete: done}
);
}
}
}
])
$scope.hasTransitions = Modernizr.csstransitions;
Build custom Modernizr
http://modernizr.com/download/
Controller
<div ng-if="pickBest"
class="example-block"
ng-class="{
'fade-in-out': hasTransitions,
'fade-in-out-js': !hasTransitions}"
>
View
angular.module('angular-examples.animations')
.animation('.fade-in-out', ['TweenMax', 'Modernizr',
function(TweenMax, Modernizr) {
if (!Modernizr.csstransitions) {
return {
enter: function(element, done) {
// Some sort of animation
},
leave: function(element, done) {
// Some sort of animation
}
}
}
return {};
}
])
;
Then just let CSS animation play