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

Commit 25c1158

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 f7a4b48 commit 25c1158

File tree

2 files changed

+35
-3
lines changed

2 files changed

+35
-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

+25-3
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,20 @@ 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 enterComplete = false;
1010+
$animate.enter(element, parent).done(function() {
1011+
enterComplete = true;
1012+
});
1013+
1014+
expect(enterComplete).toBe(false);
1015+
$animate.leave(element);
1016+
$$rAF.flush();
1017+
expect(enterComplete).toBe(true);
1018+
}));
1019+
10061020
it('should skip the class-based animation entirely if there is an active structural animation',
10071021
inject(function($animate, $rootScope) {
10081022

@@ -1136,12 +1150,20 @@ describe("animations", function() {
11361150
it('class-based animations, however it should also cancel former structural animations in the process',
11371151
inject(function($animate, $rootScope) {
11381152

1139-
element.addClass('green');
1153+
element.addClass('green lime');
11401154

11411155
$animate.enter(element, parent);
11421156
$animate.addClass(element, 'red');
11431157
$animate.removeClass(element, 'green');
1158+
11441159
$animate.leave(element);
1160+
$animate.addClass(element, 'pink');
1161+
$animate.removeClass(element, 'lime');
1162+
1163+
expect(element).toHaveClass('red');
1164+
expect(element).not.toHaveClass('green');
1165+
expect(element).not.toHaveClass('pink');
1166+
expect(element).toHaveClass('lime');
11451167

11461168
$rootScope.$digest();
11471169

@@ -1152,8 +1174,8 @@ describe("animations", function() {
11521174
expect(element.parent()[0]).toEqual(parent[0]);
11531175

11541176
options = capturedAnimation[2];
1155-
expect(options.addClass).toEqual('red');
1156-
expect(options.removeClass).toEqual('green');
1177+
expect(options.addClass).toEqual('pink');
1178+
expect(options.removeClass).toEqual('lime');
11571179
}));
11581180

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

0 commit comments

Comments
 (0)