diff --git a/src/ngAnimate/animateQueue.js b/src/ngAnimate/animateQueue.js index 00dd4e3e62db..f00d7d08a1e8 100644 --- a/src/ngAnimate/animateQueue.js +++ b/src/ngAnimate/animateQueue.js @@ -58,6 +58,14 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { return currentAnimation.state === RUNNING_STATE && newAnimation.structural; }); + rules.cancel.push(function(element, newAnimation, currentAnimation) { + var nO = newAnimation.options; + var cO = currentAnimation.options; + + // if the exact same CSS class is added/removed then it's safe to cancel it + return (nO.addClass && nO.addClass === cO.removeClass) || (nO.removeClass && nO.removeClass === cO.addClass); + }); + this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap', '$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite', function($$rAF, $rootScope, $rootElement, $document, $$HashMap, diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js index cf4d4fefd45a..c0839a0f3b3b 100644 --- a/test/ngAnimate/animateSpec.js +++ b/test/ngAnimate/animateSpec.js @@ -876,6 +876,51 @@ describe("animations", function() { expect(enterComplete).toBe(true); })); + it('should cancel the previously running removeClass animation if a follow-up addClass animation is using the same class value', + inject(function($animate, $rootScope, $$rAF) { + + parent.append(element); + var runner = $animate.addClass(element, 'active-class'); + $rootScope.$digest(); + + var closed = false; + runner.done(function(status) { + closed = true; + }); + + $$rAF.flush(); + + expect(closed).toBe(false); + + $animate.removeClass(element, 'active-class'); + $rootScope.$digest(); + + expect(closed).toBe(true); + })); + + it('should cancel the previously running addClass animation if a follow-up removeClass animation is using the same class value', + inject(function($animate, $rootScope, $$rAF) { + + element.addClass('active-class'); + parent.append(element); + var runner = $animate.removeClass(element, 'active-class'); + $rootScope.$digest(); + + var closed = false; + runner.done(function(status) { + closed = true; + }); + + $$rAF.flush(); + + expect(closed).toBe(false); + + $animate.addClass(element, 'active-class'); + $rootScope.$digest(); + + expect(closed).toBe(true); + })); + it('should skip the class-based animation entirely if there is an active structural animation', inject(function($animate, $rootScope) {