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

Commit f619d03

Browse files
committed
fix($animate): clear the GCS cache even when no animation is detected
$animate will cache subsequent calls to GCS in the event that the element with the same CSS classes and the same parentNode is being animated. Once the animation is started then $animate waits for one rAF before flushing the GCS lookup cache. Prior to this fix, if GCS was unable to detect any transitions or keyframes on the element then it would simply close the animation, but it would not trigger the rAF code to flush the cache. This issue caused a bug which made it difficult to detect why certain animations are not allowed to fire if the element didn't contain any CSS-based animations beforehand. Closes #8813
1 parent 95f5b86 commit f619d03

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

src/ngAnimate/animate.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,16 @@ angular.module('ngAnimate', ['ng'])
11561156
var parentCounter = 0;
11571157
var animationReflowQueue = [];
11581158
var cancelAnimationReflow;
1159+
function clearCacheAfterReflow() {
1160+
if (!cancelAnimationReflow) {
1161+
cancelAnimationReflow = $$animateReflow(function() {
1162+
animationReflowQueue = [];
1163+
cancelAnimationReflow = null;
1164+
lookupCache = {};
1165+
});
1166+
}
1167+
}
1168+
11591169
function afterReflow(element, callback) {
11601170
if(cancelAnimationReflow) {
11611171
cancelAnimationReflow();
@@ -1524,7 +1534,8 @@ angular.module('ngAnimate', ['ng'])
15241534
//cancellation function then it means that there is no animation
15251535
//to perform at all
15261536
var preReflowCancellation = animateBefore(animationEvent, element, className);
1527-
if(!preReflowCancellation) {
1537+
if (!preReflowCancellation) {
1538+
clearCacheAfterReflow();
15281539
animationComplete();
15291540
return;
15301541
}
@@ -1599,6 +1610,7 @@ angular.module('ngAnimate', ['ng'])
15991610
});
16001611
return cancellationMethod;
16011612
}
1613+
clearCacheAfterReflow();
16021614
animationCompleted();
16031615
},
16041616

@@ -1623,6 +1635,7 @@ angular.module('ngAnimate', ['ng'])
16231635
});
16241636
return cancellationMethod;
16251637
}
1638+
clearCacheAfterReflow();
16261639
animationCompleted();
16271640
},
16281641

test/ngAnimate/animateSpec.js

+58
Original file line numberDiff line numberDiff line change
@@ -3159,6 +3159,64 @@ describe("ngAnimate", function() {
31593159
});
31603160

31613161

3162+
it("should reset the getComputedStyle lookup cache even when no animation is found",
3163+
inject(function($compile, $rootScope, $animate, $sniffer, $document) {
3164+
3165+
if (!$sniffer.transitions) return;
3166+
3167+
$animate.enabled();
3168+
3169+
var html = '<div>' +
3170+
' <div class="toggle" ng-if="onOff">On or Off</div>' +
3171+
'</div>';
3172+
3173+
ss.addRule('.activated .toggle', '-webkit-transition:1s linear all;' +
3174+
'transition:1s linear all;');
3175+
3176+
var child, element = $compile(html)($rootScope);
3177+
3178+
$rootElement.append(element);
3179+
jqLite($document[0].body).append($rootElement);
3180+
3181+
$rootScope.onOff = true;
3182+
$rootScope.$digest();
3183+
3184+
child = element.find('div');
3185+
expect(child).not.toHaveClass('ng-enter');
3186+
expect(child.parent()[0]).toEqual(element[0]);
3187+
$animate.triggerReflow();
3188+
3189+
$rootScope.onOff = false;
3190+
$rootScope.$digest();
3191+
3192+
child = element.find('div');
3193+
expect(child.parent().length).toBe(0);
3194+
$animate.triggerReflow();
3195+
3196+
element.addClass('activated');
3197+
$rootScope.$digest();
3198+
$animate.triggerReflow();
3199+
3200+
$rootScope.onOff = true;
3201+
$rootScope.$digest();
3202+
3203+
child = element.find('div');
3204+
expect(child).toHaveClass('ng-enter');
3205+
$animate.triggerReflow();
3206+
expect(child).toHaveClass('ng-enter-active');
3207+
3208+
browserTrigger(child, 'transitionend',
3209+
{ timeStamp: Date.now() + 1000, elapsedTime: 2000 });
3210+
3211+
$animate.triggerCallbacks();
3212+
3213+
$rootScope.onOff = false;
3214+
$rootScope.$digest();
3215+
3216+
expect(child).toHaveClass('ng-leave');
3217+
$animate.triggerReflow();
3218+
expect(child).toHaveClass('ng-leave-active');
3219+
}));
31623220

31633221
it("should cancel and perform the dom operation only after the reflow has run",
31643222
inject(function($compile, $rootScope, $animate, $sniffer, $timeout) {

0 commit comments

Comments
 (0)