From eefa596c27ead030447b3f2eb23a17a11eed0f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Niemel=C3=A4?= Date: Tue, 28 Apr 2015 17:17:21 -0700 Subject: [PATCH] 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 #11717 --- src/ngAnimate/animateQueue.js | 8 +++++++ test/ngAnimate/animateSpec.js | 45 +++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) 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) {