diff --git a/src/ngAnimate/animateCss.js b/src/ngAnimate/animateCss.js index f706e13c06a2..8570ea313798 100644 --- a/src/ngAnimate/animateCss.js +++ b/src/ngAnimate/animateCss.js @@ -894,10 +894,16 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { function onAnimationExpired() { var animationsData = element.data(ANIMATE_TIMER_KEY); - for (var i = 1; i < animationsData.length; i++) { - animationsData[i](); + + // this will be false in the event that the element was + // removed from the DOM (via a leave animation or something + // similar) + if (animationsData) { + for (var i = 1; i < animationsData.length; i++) { + animationsData[i](); + } + element.removeData(ANIMATE_TIMER_KEY); } - element.removeData(ANIMATE_TIMER_KEY); } function onAnimationProgress(event) { diff --git a/test/ngAnimate/animateCssSpec.js b/test/ngAnimate/animateCssSpec.js index e06dd6dcc764..6a68556e298b 100644 --- a/test/ngAnimate/animateCssSpec.js +++ b/test/ngAnimate/animateCssSpec.js @@ -1198,6 +1198,24 @@ describe("ngAnimate $animateCss", function() { return animator; } })); + + it("should not throw an error any pending timeout requests resolve after the element has already been removed", + inject(function($animateCss, $$body, $rootElement, $timeout, $animate) { + + var element = jqLite('
'); + $rootElement.append(element); + $$body.append($rootElement); + + ss.addRule('.red', 'transition:1s linear all;'); + + $animateCss(element, { addClass: 'red' }).start(); + triggerAnimationStartFrame(); + element.remove(); + + expect(function() { + $timeout.flush(); + }).not.toThrow(); + })); }); describe("getComputedStyle", function() {