diff --git a/src/ngAnimate/animateQueue.js b/src/ngAnimate/animateQueue.js index 146e538a1508..67fb01e75736 100644 --- a/src/ngAnimate/animateQueue.js +++ b/src/ngAnimate/animateQueue.js @@ -82,6 +82,11 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { }); rules.cancel.push(function(element, newAnimation, currentAnimation) { + // cancel the animation if classes added / removed in both animation cancel each other out, + // but only if the current animation isn't structural + + if (currentAnimation.structural) return false; + var nA = newAnimation.addClass; var nR = newAnimation.removeClass; var cA = currentAnimation.addClass; diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js index bed63f270d6e..92424ed3f107 100644 --- a/test/ngAnimate/animateSpec.js +++ b/test/ngAnimate/animateSpec.js @@ -1104,7 +1104,8 @@ describe("animations", function() { $animate.removeClass(element, 'active-class'); $rootScope.$digest(); - expect(doneHandler).toHaveBeenCalled(); + // true = rejected + expect(doneHandler).toHaveBeenCalledWith(true); })); it('should cancel the previously running removeClass animation if a follow-up addClass animation is using the same class value', @@ -1123,7 +1124,8 @@ describe("animations", function() { $animate.addClass(element, 'active-class'); $rootScope.$digest(); - expect(doneHandler).toHaveBeenCalled(); + // true = rejected + expect(doneHandler).toHaveBeenCalledWith(true); })); it('should merge a follow-up animation that does not add classes into the previous animation (pre-digest)', @@ -1198,6 +1200,29 @@ describe("animations", function() { expect(capturedAnimation[2].addClass).toBe('blue'); })); + + it('should NOT cancel a previously joined addClass+structural animation if a follow-up ' + + 'removeClass animation is using the same class value (pre-digest)', + inject(function($animate, $rootScope) { + + var runner = $animate.enter(element, parent); + $animate.addClass(element, 'active-class'); + + var doneHandler = jasmine.createSpy('enter done'); + runner.done(doneHandler); + + expect(doneHandler).not.toHaveBeenCalled(); + + $animate.removeClass(element, 'active-class'); + $rootScope.$digest(); + + expect(capturedAnimation[1]).toBe('enter'); + expect(capturedAnimation[2].addClass).toBe(null); + expect(capturedAnimation[2].removeClass).toBe(null); + + expect(doneHandler).not.toHaveBeenCalled(); + })); + }); describe('should merge', function() { diff --git a/test/ngAnimate/integrationSpec.js b/test/ngAnimate/integrationSpec.js index 80e580d1d87a..25553298f1bb 100644 --- a/test/ngAnimate/integrationSpec.js +++ b/test/ngAnimate/integrationSpec.js @@ -756,5 +756,43 @@ describe('ngAnimate integration tests', function() { expect(child.attr('style')).toContain('50px'); }); }); + + + it('should execute the enter animation on a