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

Commit 2327f5a

Browse files
committed
fix(ngAnimate): ensure that repeated structural calls during pre-digest function
Prior to this fix if `$animate.enter()` or `$animate.leave()` was called before a digest was issued then the element may not be cancelled early enough. This fix ensures that the previous structural animation is cancelled immediately when a follow-up animation is kicked off. Closes #11867
1 parent 718ff84 commit 2327f5a

File tree

2 files changed

+33
-3
lines changed

2 files changed

+33
-3
lines changed

src/ngAnimate/animateQueue.js

+10
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
292292
structural: isStructural,
293293
element: element,
294294
event: event,
295+
close: close,
295296
options: options,
296297
runner: runner
297298
};
@@ -311,8 +312,17 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
311312
var cancelAnimationFlag = isAllowed('cancel', element, newAnimation, existingAnimation);
312313
if (cancelAnimationFlag) {
313314
if (existingAnimation.state === RUNNING_STATE) {
315+
// this will end the animation right away and it is safe
316+
// to do so since the animation is already running and the
317+
// runner callback code will run in async
314318
existingAnimation.runner.end();
319+
} else if (existingAnimation.structural) {
320+
// this means that the animation is queued into a digest, but
321+
// hasn't started yet. Therefore it is safe to run the close
322+
// method which will call the runner methods in async.
323+
existingAnimation.close();
315324
} else {
325+
// this will merge the existing animation options into this new follow-up animation
316326
mergeAnimationOptions(element, newAnimation.options, existingAnimation.options);
317327
}
318328
} else {

test/ngAnimate/animateSpec.js

+23-3
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,18 @@ describe("animations", function() {
10031003
expect(enterComplete).toBe(true);
10041004
}));
10051005

1006+
it('should cancel the previous structural animation if a follow-up structural animation takes over before the postDigest',
1007+
inject(function($animate, $$rAF) {
1008+
1009+
var enterDone = jasmine.createSpy('enter animation done');
1010+
$animate.enter(element, parent).done(enterDone);
1011+
expect(enterDone).not.toHaveBeenCalled();
1012+
1013+
$animate.leave(element);
1014+
$$rAF.flush();
1015+
expect(enterDone).toHaveBeenCalled();
1016+
}));
1017+
10061018
it('should skip the class-based animation entirely if there is an active structural animation',
10071019
inject(function($animate, $rootScope) {
10081020

@@ -1152,12 +1164,20 @@ describe("animations", function() {
11521164
it('class-based animations, however it should also cancel former structural animations in the process',
11531165
inject(function($animate, $rootScope) {
11541166

1155-
element.addClass('green');
1167+
element.addClass('green lime');
11561168

11571169
$animate.enter(element, parent);
11581170
$animate.addClass(element, 'red');
11591171
$animate.removeClass(element, 'green');
1172+
11601173
$animate.leave(element);
1174+
$animate.addClass(element, 'pink');
1175+
$animate.removeClass(element, 'lime');
1176+
1177+
expect(element).toHaveClass('red');
1178+
expect(element).not.toHaveClass('green');
1179+
expect(element).not.toHaveClass('pink');
1180+
expect(element).toHaveClass('lime');
11611181

11621182
$rootScope.$digest();
11631183

@@ -1168,8 +1188,8 @@ describe("animations", function() {
11681188
expect(element.parent()[0]).toEqual(parent[0]);
11691189

11701190
options = capturedAnimation[2];
1171-
expect(options.addClass).toEqual('red');
1172-
expect(options.removeClass).toEqual('green');
1191+
expect(options.addClass).toEqual('pink');
1192+
expect(options.removeClass).toEqual('lime');
11731193
}));
11741194

11751195
it('should retain the instance to the very first runner object when multiple element-level animations are issued',

0 commit comments

Comments
 (0)