Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit ea4120b

Browse files
committed
feat(ngAnimate): let $animate.off() remove all listeners for an element
1 parent c75fb80 commit ea4120b

File tree

3 files changed

+86
-10
lines changed

3 files changed

+86
-10
lines changed

src/ng/animate.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,9 @@ var $AnimateProvider = ['$provide', function($provide) {
326326
* // remove all the animation event listeners listening for `enter`
327327
* $animate.off('enter');
328328
*
329+
* // remove listeners for all animation events from the container element
330+
* $animate.off(container);
331+
*
329332
* // remove all the animation event listeners listening for `enter` on the given element and its children
330333
* $animate.off('enter', container);
331334
*
@@ -334,7 +337,9 @@ var $AnimateProvider = ['$provide', function($provide) {
334337
* $animate.off('enter', container, callback);
335338
* ```
336339
*
337-
* @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...)
340+
* @param {string|DOMElement} event|container the animation event (e.g. enter, leave, move,
341+
* addClass, removeClass, etc...), or the container element. If it is the element, all other
342+
* arguments are ignored.
338343
* @param {DOMElement=} container the container element the event listener was placed on
339344
* @param {Function=} callback the callback function that was registered as the listener
340345
*/

src/ngAnimate/animateQueue.js

+18-9
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
199199
return matches;
200200
}
201201

202+
function filterFromRegistry(list, matchContainer, matchCallback) {
203+
var containerNode = extractElementNode(matchContainer);
204+
return list.filter(function(entry) {
205+
var isMatch = entry.node === containerNode &&
206+
(!matchCallback || entry.callback === matchCallback);
207+
return !isMatch;
208+
});
209+
}
210+
202211
var $animate = {
203212
on: function(event, container, callback) {
204213
var node = extractElementNode(container);
@@ -215,21 +224,21 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
215224
},
216225

217226
off: function(event, container, callback) {
227+
if (arguments.length === 1 && !angular.isString(arguments[0])) {
228+
container = arguments[0];
229+
for (var eventType in callbackRegistry) {
230+
callbackRegistry[eventType] = filterFromRegistry(callbackRegistry[eventType], container);
231+
}
232+
233+
return;
234+
}
235+
218236
var entries = callbackRegistry[event];
219237
if (!entries) return;
220238

221239
callbackRegistry[event] = arguments.length === 1
222240
? null
223241
: filterFromRegistry(entries, container, callback);
224-
225-
function filterFromRegistry(list, matchContainer, matchCallback) {
226-
var containerNode = extractElementNode(matchContainer);
227-
return list.filter(function(entry) {
228-
var isMatch = entry.node === containerNode &&
229-
(!matchCallback || entry.callback === matchCallback);
230-
return !isMatch;
231-
});
232-
}
233242
},
234243

235244
pin: function(element, parentElement) {

test/ngAnimate/animateSpec.js

+62
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,68 @@ describe("animations", function() {
18961896
expect(count).toBe(3);
18971897
}));
18981898

1899+
it('should remove all event listeners for an element when $animate.off(element) is called',
1900+
inject(function($animate, $rootScope, $rootElement, $document, $$rAF) {
1901+
1902+
element = jqLite('<div></div>');
1903+
var otherElement = jqLite('<div></div>');
1904+
$rootElement.append(otherElement);
1905+
1906+
var count = 0;
1907+
var runner;
1908+
$animate.on('enter', element, counter);
1909+
$animate.on('leave', element, counter);
1910+
$animate.on('addClass', element, counter);
1911+
$animate.on('addClass', otherElement, counter);
1912+
1913+
function counter(element, phase) {
1914+
count++;
1915+
}
1916+
1917+
runner = $animate.enter(element, $rootElement);
1918+
$rootScope.$digest();
1919+
$animate.flush();
1920+
runner.end();
1921+
1922+
runner = $animate.addClass(element, 'blue');
1923+
$rootScope.$digest();
1924+
$animate.flush();
1925+
1926+
runner.end();
1927+
$$rAF.flush();
1928+
1929+
expect(count).toBe(4);
1930+
1931+
$animate.off(element);
1932+
1933+
runner = $animate.enter(element, $rootElement);
1934+
$animate.flush();
1935+
expect(capturedAnimation[1]).toBe('enter');
1936+
runner.end();
1937+
1938+
runner = $animate.addClass(element, 'red');
1939+
$animate.flush();
1940+
expect(capturedAnimation[1]).toBe('addClass');
1941+
runner.end();
1942+
1943+
runner = $animate.leave(element);
1944+
$animate.flush();
1945+
expect(capturedAnimation[1]).toBe('leave');
1946+
runner.end();
1947+
1948+
// Try to flush all remaining callbacks
1949+
expect(function() {
1950+
$$rAF.flush();
1951+
}).toThrowError('No rAF callbacks present');
1952+
1953+
expect(count).toBe(4);
1954+
1955+
// Check that other elements' event listeners are not affected
1956+
$animate.addClass(otherElement, 'green');
1957+
$animate.flush();
1958+
expect(count).toBe(5);
1959+
}));
1960+
18991961
it('should fire a `start` callback when the animation starts with the matching element',
19001962
inject(function($animate, $rootScope, $rootElement, $document) {
19011963

0 commit comments

Comments
 (0)