Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit be01ceb

Browse files
committed
fix(ngAnimate): ignore children without animation data when closing them
During parent structural animations, ongoing animations on child elements are closed. These child elements are identified by their data-ng-animate attribute. If an element is the clone of an animating element, it might have this attribute, but no animation runner associated with it, so we need to ignore it. Fixes #11992 Closes #13424
1 parent 7a81e6f commit be01ceb

File tree

2 files changed

+62
-39
lines changed

2 files changed

+62
-39
lines changed

src/ngAnimate/animateQueue.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -512,15 +512,15 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
512512
forEach(children, function(child) {
513513
var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME));
514514
var animationDetails = activeAnimationsLookup.get(child);
515-
switch (state) {
516-
case RUNNING_STATE:
517-
animationDetails.runner.end();
518-
/* falls through */
519-
case PRE_DIGEST_STATE:
520-
if (animationDetails) {
515+
if (animationDetails) {
516+
switch (state) {
517+
case RUNNING_STATE:
518+
animationDetails.runner.end();
519+
/* falls through */
520+
case PRE_DIGEST_STATE:
521521
activeAnimationsLookup.remove(child);
522-
}
523-
break;
522+
break;
523+
}
524524
}
525525
});
526526
}

test/ngAnimate/animateSpec.js

+54-31
Original file line numberDiff line numberDiff line change
@@ -834,47 +834,70 @@ describe("animations", function() {
834834
expect(capturedAnimation[0]).toBe(element);
835835
}));
836836

837-
it('should skip all pre-digest queued child animations when a parent structural animation is triggered',
838-
inject(function($rootScope, $rootElement, $animate) {
837+
describe('when a parent structural animation is triggered:', function() {
839838

840-
parent.append(element);
839+
it('should skip all pre-digest queued child animations',
840+
inject(function($rootScope, $rootElement, $animate) {
841841

842-
$animate.addClass(element, 'rumlow');
843-
$animate.move(parent, null, parent2);
842+
parent.append(element);
844843

845-
expect(capturedAnimation).toBeFalsy();
846-
expect(capturedAnimationHistory.length).toBe(0);
847-
$rootScope.$digest();
844+
$animate.addClass(element, 'rumlow');
845+
$animate.move(parent, null, parent2);
848846

849-
expect(capturedAnimation[0]).toBe(parent);
850-
expect(capturedAnimationHistory.length).toBe(1);
851-
}));
847+
expect(capturedAnimation).toBeFalsy();
848+
expect(capturedAnimationHistory.length).toBe(0);
849+
$rootScope.$digest();
852850

853-
it('should end all ongoing post-digest child animations when a parent structural animation is triggered',
854-
inject(function($rootScope, $rootElement, $animate) {
851+
expect(capturedAnimation[0]).toBe(parent);
852+
expect(capturedAnimationHistory.length).toBe(1);
853+
}));
855854

856-
parent.append(element);
855+
it('should end all ongoing post-digest child animations',
856+
inject(function($rootScope, $rootElement, $animate) {
857857

858-
$animate.addClass(element, 'rumlow');
859-
var isCancelled = false;
860-
overriddenAnimationRunner = extend(defaultFakeAnimationRunner, {
861-
end: function() {
862-
isCancelled = true;
863-
}
864-
});
858+
parent.append(element);
865859

866-
$rootScope.$digest();
867-
expect(capturedAnimation[0]).toBe(element);
868-
expect(isCancelled).toBe(false);
860+
$animate.addClass(element, 'rumlow');
861+
var isCancelled = false;
862+
overriddenAnimationRunner = extend(defaultFakeAnimationRunner, {
863+
end: function() {
864+
isCancelled = true;
865+
}
866+
});
869867

870-
// restore the default
871-
overriddenAnimationRunner = defaultFakeAnimationRunner;
872-
$animate.move(parent, null, parent2);
873-
$rootScope.$digest();
874-
expect(capturedAnimation[0]).toBe(parent);
868+
$rootScope.$digest();
869+
expect(capturedAnimation[0]).toBe(element);
870+
expect(isCancelled).toBe(false);
875871

876-
expect(isCancelled).toBe(true);
877-
}));
872+
// restore the default
873+
overriddenAnimationRunner = defaultFakeAnimationRunner;
874+
$animate.move(parent, null, parent2);
875+
$rootScope.$digest();
876+
expect(capturedAnimation[0]).toBe(parent);
877+
878+
expect(isCancelled).toBe(true);
879+
}));
880+
881+
it('should ignore children that have animation data-attributes but no animation data',
882+
inject(function($rootScope, $rootElement, $animate) {
883+
884+
parent.append(element);
885+
886+
$animate.addClass(element, 'rumlow');
887+
888+
$rootScope.$digest();
889+
expect(capturedAnimation[0]).toBe(element);
890+
891+
// If an element is cloned during an animation, the clone has the data-attributes indicating
892+
// an animation
893+
var clone = element.clone();
894+
parent.append(clone);
895+
896+
$animate.move(parent, null, parent2);
897+
$rootScope.$digest();
898+
expect(capturedAnimation[0]).toBe(parent);
899+
}));
900+
});
878901

879902
it('should not end any child animations if a parent class-based animation is issued',
880903
inject(function($rootScope, $rootElement, $animate) {

0 commit comments

Comments
 (0)