Skip to content

Commit e166621

Browse files
committed
fix(ngAnimate.$animate): remove animation callbacks when the element is removed
The test for this didn't actually test the listener removal. The addClass animation after the element removal didn't start because the enter animation was still in progress.
1 parent a1010c5 commit e166621

File tree

2 files changed

+43
-8
lines changed

2 files changed

+43
-8
lines changed

src/ngAnimate/animateQueue.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,19 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
194194
return matches;
195195
}
196196

197-
return {
197+
var $animate = {
198198
on: function(event, container, callback) {
199199
var node = extractElementNode(container);
200200
callbackRegistry[event] = callbackRegistry[event] || [];
201201
callbackRegistry[event].push({
202202
node: node,
203203
callback: callback
204204
});
205+
206+
// Remove the callback when the element is removed from the DOM
207+
jqLite(container).on('$destroy', function() {
208+
$animate.off(event, container, callback);
209+
});
205210
},
206211

207212
off: function(event, container, callback) {
@@ -269,6 +274,8 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
269274
}
270275
};
271276

277+
return $animate;
278+
272279
function queueAnimation(element, event, initialOptions) {
273280
// we always make a copy of the options since
274281
// there should never be any side effects on

test/ngAnimate/animateSpec.js

+35-7
Original file line numberDiff line numberDiff line change
@@ -1912,33 +1912,62 @@ describe("animations", function() {
19121912
expect(capturedElement).toBe(element);
19131913
}));
19141914

1915-
it('should remove the event listener if the element is removed',
1915+
it('should remove all event listeners when the element is removed',
19161916
inject(function($animate, $rootScope, $rootElement) {
19171917

19181918
element = jqLite('<div></div>');
19191919

19201920
var count = 0;
1921+
var runner;
1922+
19211923
$animate.on('enter', element, counter);
1922-
$animate.on('addClass', element, counter);
1924+
$animate.on('addClass', element[0], counter);
19231925

19241926
function counter(element, phase) {
19251927
if (phase === 'start') {
19261928
count++;
19271929
}
19281930
}
19291931

1930-
$animate.enter(element, $rootElement);
1932+
runner = $animate.enter(element, $rootElement);
19311933
$rootScope.$digest();
1932-
$animate.flush();
1934+
expect(capturedAnimation).toBeTruthy();
19331935

1936+
$animate.flush();
1937+
runner.end(); // Otherwise the class animation won't run because enter is still in progress
19341938
expect(count).toBe(1);
1939+
1940+
capturedAnimation = null;
1941+
1942+
$animate.addClass(element, 'blue');
1943+
$rootScope.$digest();
1944+
expect(capturedAnimation).toBeTruthy();
1945+
1946+
$animate.flush();
1947+
expect(count).toBe(2);
1948+
1949+
capturedAnimation = null;
1950+
19351951
element.remove();
19361952

1937-
$animate.addClass(element, 'viljami');
1953+
runner = $animate.enter(element, $rootElement);
19381954
$rootScope.$digest();
19391955

1956+
expect(capturedAnimation).toBeTruthy();
1957+
19401958
$animate.flush();
1941-
expect(count).toBe(1);
1959+
runner.end(); // Otherwise the class animation won't run because enter is still in progress
1960+
1961+
expect(count).toBe(2);
1962+
1963+
capturedAnimation = null;
1964+
1965+
$animate.addClass(element, 'red');
1966+
$rootScope.$digest();
1967+
expect(capturedAnimation).toBeTruthy();
1968+
1969+
$animate.flush();
1970+
expect(count).toBe(2);
19421971
}));
19431972

19441973
it('should always detect registered callbacks after one postDigest has fired',
@@ -2116,7 +2145,6 @@ describe("animations", function() {
21162145

21172146
var callbackTriggered = false;
21182147

2119-
21202148
$animate.on($event, $document[0], function() {
21212149
callbackTriggered = true;
21222150
});

0 commit comments

Comments
 (0)