Skip to content

Commit 3105b2c

Browse files
Narretzmgol
authored andcommitted
fix(ngAnimate): remove prepare classes with multiple structural animations
Closes angular#16681 Closes angular#16677
1 parent bc5a48d commit 3105b2c

File tree

2 files changed

+83
-3
lines changed

2 files changed

+83
-3
lines changed

src/ngAnimate/animation.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro
113113

114114
// TODO(matsko): document the signature in a better way
115115
return function(element, event, options) {
116-
var node = getDomNode(element);
117-
118116
options = prepareAnimationOptions(options);
119117
var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;
120118

@@ -186,8 +184,9 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro
186184
forEach(groupedAnimations, function(animationEntry) {
187185
var element = animationEntry.from ? animationEntry.from.element : animationEntry.element;
188186
var extraClasses = options.addClass;
187+
189188
extraClasses = (extraClasses ? (extraClasses + ' ') : '') + NG_ANIMATE_CLASSNAME;
190-
var cacheKey = $$animateCache.cacheKey(node, event, extraClasses, options.removeClass);
189+
var cacheKey = $$animateCache.cacheKey(element[0], animationEntry.event, extraClasses, options.removeClass);
191190

192191
toBeSortedAnimations.push({
193192
element: element,

test/ngAnimate/integrationSpec.js

+81
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ describe('ngAnimate integration tests', function() {
2525
ss.destroy();
2626
});
2727

28+
2829
it('should cancel a running and started removeClass animation when a follow-up addClass animation adds the same class',
2930
inject(function($animate, $rootScope, $$rAF, $document, $rootElement) {
3031

@@ -362,6 +363,7 @@ describe('ngAnimate integration tests', function() {
362363
});
363364
});
364365

366+
365367
it('should add the preparation class for an enter animation before a parent class-based animation is applied', function() {
366368
module('ngAnimateMock');
367369
inject(function($animate, $compile, $rootScope, $rootElement, $document) {
@@ -397,6 +399,7 @@ describe('ngAnimate integration tests', function() {
397399
});
398400
});
399401

402+
400403
it('should avoid adding the ng-enter-prepare method to a parent structural animation that contains child animations', function() {
401404
module('ngAnimateMock');
402405
inject(function($animate, $compile, $rootScope, $rootElement, $document, $$rAF) {
@@ -468,6 +471,84 @@ describe('ngAnimate integration tests', function() {
468471
});
469472
});
470473

474+
475+
it('should remove the prepare classes when different structural animations happen in the same digest', function() {
476+
module('ngAnimateMock');
477+
inject(function($animate, $compile, $rootScope, $rootElement, $document, $$animateCache) {
478+
element = jqLite(
479+
// Class animation on parent element is neeeded so the child elements get the prepare class
480+
'<div id="outer" ng-class="{blue: cond}" ng-switch="cond">' +
481+
'<div id="default" ng-switch-default></div>' +
482+
'<div id="truthy" ng-switch-when="true"></div>' +
483+
'</div>'
484+
);
485+
486+
$rootElement.append(element);
487+
jqLite($document[0].body).append($rootElement);
488+
489+
$compile(element)($rootScope);
490+
$rootScope.cond = false;
491+
$rootScope.$digest();
492+
493+
$rootScope.cond = true;
494+
$rootScope.$digest();
495+
496+
var parent = element;
497+
var truthySwitch = jqLite(parent[0].querySelector('#truthy'));
498+
var defaultSwitch = jqLite(parent[0].querySelector('#default'));
499+
500+
expect(parent).not.toHaveClass('blue');
501+
expect(parent).toHaveClass('blue-add');
502+
expect(truthySwitch).toHaveClass('ng-enter-prepare');
503+
expect(defaultSwitch).toHaveClass('ng-leave-prepare');
504+
505+
$animate.flush();
506+
507+
expect(parent).toHaveClass('blue');
508+
expect(parent).not.toHaveClass('blue-add');
509+
expect(truthySwitch).not.toHaveClass('ng-enter-prepare');
510+
expect(defaultSwitch).not.toHaveClass('ng-leave-prepare');
511+
});
512+
});
513+
514+
it('should respect the element node for caching when animations with the same type happen in the same digest', function() {
515+
module('ngAnimateMock');
516+
inject(function($animate, $compile, $rootScope, $rootElement, $document, $$animateCache) {
517+
ss.addRule('.animate.ng-enter', 'transition:2s linear all;');
518+
519+
element = jqLite(
520+
'<div>' +
521+
'<div>' +
522+
'<div id="noanimate" ng-if="cond"></div>' +
523+
'</div>' +
524+
'<div>' +
525+
'<div id="animate" class="animate" ng-if="cond"></div>' +
526+
'</div>' +
527+
'</div>'
528+
);
529+
530+
$rootElement.append(element);
531+
jqLite($document[0].body).append($rootElement);
532+
533+
$compile(element)($rootScope);
534+
$rootScope.cond = true;
535+
$rootScope.$digest();
536+
537+
var parent = element;
538+
var noanimate = jqLite(parent[0].querySelector('#noanimate'));
539+
var animate = jqLite(parent[0].querySelector('#animate'));
540+
541+
expect(noanimate).not.toHaveClass('ng-enter');
542+
expect(animate).toHaveClass('ng-enter');
543+
544+
$animate.closeAndFlush();
545+
546+
expect(noanimate).not.toHaveClass('ng-enter');
547+
expect(animate).not.toHaveClass('ng-enter');
548+
});
549+
});
550+
551+
471552
it('should pack level elements into their own RAF flush', function() {
472553
module('ngAnimateMock');
473554
inject(function($animate, $compile, $rootScope, $rootElement, $document) {

0 commit comments

Comments
 (0)