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
with ngIf that has an ' + + '', function() { + + var animationSpy = jasmine.createSpy(); + + module(function($animateProvider) { + $animateProvider.register('.animate-me', function() { + return { + enter: function(element, done) { + animationSpy(); + done(); + } + }; + }); + }); + + inject(function($animate, $rootScope, $compile) { + + element = jqLite( + '
' + + '' + + '' + + '' + + '
'); + + html(element); + + $compile(element)($rootScope); + + $rootScope.show = true; + $rootScope.$digest(); + + $animate.flush(); + expect(animationSpy).toHaveBeenCalled(); + }); + }); }); });