Skip to content

Commit

Permalink
fix(ngAnimate): ignore children without animation data when closing them
Browse files Browse the repository at this point in the history
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 angular#11992
Closes angular#13424
  • Loading branch information
Narretz committed Dec 2, 2015
1 parent 193153c commit 77419cf
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 39 deletions.
16 changes: 8 additions & 8 deletions src/ngAnimate/animateQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -512,15 +512,15 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
forEach(children, function(child) {
var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME));
var animationDetails = activeAnimationsLookup.get(child);
switch (state) {
case RUNNING_STATE:
animationDetails.runner.end();
/* falls through */
case PRE_DIGEST_STATE:
if (animationDetails) {
if (animationDetails) {
switch (state) {
case RUNNING_STATE:
animationDetails.runner.end();
/* falls through */
case PRE_DIGEST_STATE:
activeAnimationsLookup.remove(child);
}
break;
break;
}
}
});
}
Expand Down
85 changes: 54 additions & 31 deletions test/ngAnimate/animateSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -834,47 +834,70 @@ describe("animations", function() {
expect(capturedAnimation[0]).toBe(element);
}));

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

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

$animate.addClass(element, 'rumlow');
$animate.move(parent, null, parent2);
parent.append(element);

expect(capturedAnimation).toBeFalsy();
expect(capturedAnimationHistory.length).toBe(0);
$rootScope.$digest();
$animate.addClass(element, 'rumlow');
$animate.move(parent, null, parent2);

expect(capturedAnimation[0]).toBe(parent);
expect(capturedAnimationHistory.length).toBe(1);
}));
expect(capturedAnimation).toBeFalsy();
expect(capturedAnimationHistory.length).toBe(0);
$rootScope.$digest();

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

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

$animate.addClass(element, 'rumlow');
var isCancelled = false;
overriddenAnimationRunner = extend(defaultFakeAnimationRunner, {
end: function() {
isCancelled = true;
}
});
parent.append(element);

$rootScope.$digest();
expect(capturedAnimation[0]).toBe(element);
expect(isCancelled).toBe(false);
$animate.addClass(element, 'rumlow');
var isCancelled = false;
overriddenAnimationRunner = extend(defaultFakeAnimationRunner, {
end: function() {
isCancelled = true;
}
});

// restore the default
overriddenAnimationRunner = defaultFakeAnimationRunner;
$animate.move(parent, null, parent2);
$rootScope.$digest();
expect(capturedAnimation[0]).toBe(parent);
$rootScope.$digest();
expect(capturedAnimation[0]).toBe(element);
expect(isCancelled).toBe(false);

expect(isCancelled).toBe(true);
}));
// restore the default
overriddenAnimationRunner = defaultFakeAnimationRunner;
$animate.move(parent, null, parent2);
$rootScope.$digest();
expect(capturedAnimation[0]).toBe(parent);

expect(isCancelled).toBe(true);
}));

it('should ignore children that have animation data-attributes but no animation data',
inject(function($rootScope, $rootElement, $animate) {

parent.append(element);

$animate.addClass(element, 'rumlow');

$rootScope.$digest();
expect(capturedAnimation[0]).toBe(element);

// If an element is cloned during an animation, the clone has the data-attributes indicating
// an animation
var clone = element.clone();
parent.append(clone);

$animate.move(parent, null, parent2);
$rootScope.$digest();
expect(capturedAnimation[0]).toBe(parent);
}));
});

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

0 comments on commit 77419cf

Please sign in to comment.