Skip to content

Commit eefa596

Browse files
committed
fix(ngAnimate): close follow-up class-based animations when the same class is added/removed when removed/added
This patch ensures that if the same CSS class is added/removed within a follow-up digest then the previous class-based animation is cancelled beforehand. Closes angular#11717
1 parent 74eb17d commit eefa596

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

src/ngAnimate/animateQueue.js

+8
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
5858
return currentAnimation.state === RUNNING_STATE && newAnimation.structural;
5959
});
6060

61+
rules.cancel.push(function(element, newAnimation, currentAnimation) {
62+
var nO = newAnimation.options;
63+
var cO = currentAnimation.options;
64+
65+
// if the exact same CSS class is added/removed then it's safe to cancel it
66+
return (nO.addClass && nO.addClass === cO.removeClass) || (nO.removeClass && nO.removeClass === cO.addClass);
67+
});
68+
6169
this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap',
6270
'$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite',
6371
function($$rAF, $rootScope, $rootElement, $document, $$HashMap,

test/ngAnimate/animateSpec.js

+45
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,51 @@ describe("animations", function() {
876876
expect(enterComplete).toBe(true);
877877
}));
878878

879+
it('should cancel the previously running removeClass animation if a follow-up addClass animation is using the same class value',
880+
inject(function($animate, $rootScope, $$rAF) {
881+
882+
parent.append(element);
883+
var runner = $animate.addClass(element, 'active-class');
884+
$rootScope.$digest();
885+
886+
var closed = false;
887+
runner.done(function(status) {
888+
closed = true;
889+
});
890+
891+
$$rAF.flush();
892+
893+
expect(closed).toBe(false);
894+
895+
$animate.removeClass(element, 'active-class');
896+
$rootScope.$digest();
897+
898+
expect(closed).toBe(true);
899+
}));
900+
901+
it('should cancel the previously running addClass animation if a follow-up removeClass animation is using the same class value',
902+
inject(function($animate, $rootScope, $$rAF) {
903+
904+
element.addClass('active-class');
905+
parent.append(element);
906+
var runner = $animate.removeClass(element, 'active-class');
907+
$rootScope.$digest();
908+
909+
var closed = false;
910+
runner.done(function(status) {
911+
closed = true;
912+
});
913+
914+
$$rAF.flush();
915+
916+
expect(closed).toBe(false);
917+
918+
$animate.addClass(element, 'active-class');
919+
$rootScope.$digest();
920+
921+
expect(closed).toBe(true);
922+
}));
923+
879924
it('should skip the class-based animation entirely if there is an active structural animation',
880925
inject(function($animate, $rootScope) {
881926

0 commit comments

Comments
 (0)