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

Commit cb85cbc

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 a75546a commit cb85cbc

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

src/ngAnimate/animate.js

+14
Original file line numberDiff line numberDiff line change
@@ -1419,6 +1419,16 @@ angular.module('ngAnimate', ['ng'])
14191419
var parentCounter = 0;
14201420
var animationReflowQueue = [];
14211421
var cancelAnimationReflow;
1422+
function clearCacheAfterReflow() {
1423+
if (!cancelAnimationReflow) {
1424+
cancelAnimationReflow = $$animateReflow(function() {
1425+
animationReflowQueue = [];
1426+
cancelAnimationReflow = null;
1427+
lookupCache = {};
1428+
});
1429+
}
1430+
}
1431+
14221432
function afterReflow(element, callback) {
14231433
if (cancelAnimationReflow) {
14241434
cancelAnimationReflow();
@@ -1764,6 +1774,7 @@ angular.module('ngAnimate', ['ng'])
17641774
//to perform at all
17651775
var preReflowCancellation = animateBefore(animationEvent, element, className);
17661776
if (!preReflowCancellation) {
1777+
clearCacheAfterReflow();
17671778
animationComplete();
17681779
return;
17691780
}
@@ -1820,6 +1831,7 @@ angular.module('ngAnimate', ['ng'])
18201831
afterReflow(element, animationCompleted);
18211832
return cancellationMethod;
18221833
}
1834+
clearCacheAfterReflow();
18231835
animationCompleted();
18241836
},
18251837

@@ -1829,6 +1841,7 @@ angular.module('ngAnimate', ['ng'])
18291841
afterReflow(element, animationCompleted);
18301842
return cancellationMethod;
18311843
}
1844+
clearCacheAfterReflow();
18321845
animationCompleted();
18331846
},
18341847

@@ -1838,6 +1851,7 @@ angular.module('ngAnimate', ['ng'])
18381851
afterReflow(element, animationCompleted);
18391852
return cancellationMethod;
18401853
}
1854+
clearCacheAfterReflow();
18411855
animationCompleted();
18421856
},
18431857

test/ngAnimate/animateSpec.js

+58
Original file line numberDiff line numberDiff line change
@@ -3757,6 +3757,64 @@ describe("ngAnimate", function() {
37573757
expect(inner.hasClass('on-add-active')).toBe(false);
37583758
}));
37593759

3760+
it("should reset the getComputedStyle lookup cache even when no animation is found",
3761+
inject(function($compile, $rootScope, $animate, $sniffer, $document) {
3762+
3763+
if (!$sniffer.transitions) return;
3764+
3765+
$animate.enabled();
3766+
3767+
var html = '<div>' +
3768+
' <div class="toggle" ng-if="onOff">On or Off</div>' +
3769+
'</div>';
3770+
3771+
ss.addRule('.activated .toggle', '-webkit-transition:1s linear all;' +
3772+
'transition:1s linear all;');
3773+
3774+
var child, element = $compile(html)($rootScope);
3775+
3776+
$rootElement.append(element);
3777+
jqLite($document[0].body).append($rootElement);
3778+
3779+
$rootScope.onOff = true;
3780+
$rootScope.$digest();
3781+
3782+
child = element.find('div');
3783+
expect(child).not.toHaveClass('ng-enter');
3784+
expect(child.parent()[0]).toEqual(element[0]);
3785+
$animate.triggerReflow();
3786+
3787+
$rootScope.onOff = false;
3788+
$rootScope.$digest();
3789+
3790+
child = element.find('div');
3791+
expect(child.parent().length).toBe(0);
3792+
$animate.triggerReflow();
3793+
3794+
element.addClass('activated');
3795+
$rootScope.$digest();
3796+
$animate.triggerReflow();
3797+
3798+
$rootScope.onOff = true;
3799+
$rootScope.$digest();
3800+
3801+
child = element.find('div');
3802+
expect(child).toHaveClass('ng-enter');
3803+
$animate.triggerReflow();
3804+
expect(child).toHaveClass('ng-enter-active');
3805+
3806+
browserTrigger(child, 'transitionend',
3807+
{ timeStamp: Date.now() + 1000, elapsedTime: 2000 });
3808+
3809+
$animate.triggerCallbacks();
3810+
3811+
$rootScope.onOff = false;
3812+
$rootScope.$digest();
3813+
3814+
expect(child).toHaveClass('ng-leave');
3815+
$animate.triggerReflow();
3816+
expect(child).toHaveClass('ng-leave-active');
3817+
}));
37603818

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

0 commit comments

Comments
 (0)