ngAnimate: Animating Both Ancestor and Descendent Elements at the Same Time
By default, Angular JS applies a rule for animations: a child element's animation will be skipped if an ancestor element is already being animated. I'm not sure why this policy exists, but this is what will trip you up if you try to:
This policy sure caused me some painful troubleshooting sessions, so I'll show you where this policy is enforced in Angular and how to override this default rule.
This is the function which checks whether or not to run an animation when $animate.enter / $animate.leave etc are called: https://github.com/angular/angular.js/blob/v1.3.13/src/ngAnimate/animate.js#L1296. The policy of not allowing descendent elements to animate when an ancestor is being animated is stated here.
If you scroll down to the animationsDisabled function, you can see what Angular actually checks for. You will also see a mysterious check for an NG_ANIMATE_CHILDREN data attribute. This is the undocumented secret which will let us override Angular's default policy of no nested animations!
Here's how you use NG_ANIMATE_CHILDREN.
Sample HTML:
- animate in child elements while a page transition is taking place,
- fade in some content while performing a full-page reveal upon page load,
- etc
This policy sure caused me some painful troubleshooting sessions, so I'll show you where this policy is enforced in Angular and how to override this default rule.
This is the function which checks whether or not to run an animation when $animate.enter / $animate.leave etc are called: https://github.com/angular/angular.js/blob/v1.3.13/src/ngAnimate/animate.js#L1296. The policy of not allowing descendent elements to animate when an ancestor is being animated is stated here.
If you scroll down to the animationsDisabled function, you can see what Angular actually checks for. You will also see a mysterious check for an NG_ANIMATE_CHILDREN data attribute. This is the undocumented secret which will let us override Angular's default policy of no nested animations!
Here's how you use NG_ANIMATE_CHILDREN.
Sample HTML:
<body ng-app="exampleApp">
<div class="someAnimatedParent">
<div class="someAnimatedChild">
Why won't Angular let me animate?
</div>
</div>
</body>
In your script, for example in exampleApp.run(), add this line:
$(".someAnimatedParent").data("$$ngAnimateChildren", true)
Once the script runs, any element within .someAnimatedParent will be animatable even if .someAnimatedParent itself is also running an animation. That's all you have to do!
Notes:
- You can of course set the data attribute on the <body> element, in which case all elements will animate whether their parents are animating or not.
- We have to set the data attribute using a script because of the funny characters and uppercases. If anyone knows how to insert such an attribute in HTML directly, please send me a note on Github or Twitter!
- This code was tested with Angular JS 1.3.13.
If you are unsure whether you are facing this problem, check if the promise returned by $animate.enter() is immediately resolved, without calling any animations defined by yourAppModule.animation(). If that is the case, you may be facing the issue described here.