mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-22 01:10:23 +00:00
feat(scope): add listener deregistration fn for $watch and $on
- both $watch and $on now return a function which when called deregisters the listener - $removeListener was removed and replaced with the above - added more tests for $watch and $on Closes #542
This commit is contained in:
parent
a5607e3061
commit
31b8624121
2 changed files with 94 additions and 45 deletions
51
src/Scope.js
51
src/Scope.js
|
|
@ -257,22 +257,29 @@ Scope.prototype = {
|
|||
* - `string`: Evaluated as {@link guide/dev_guide.expressions expression}
|
||||
* - `function(scope, newValue, oldValue)`: called with current `scope` an previous and
|
||||
* current values as parameters.
|
||||
* @returns {function()} Returns a deregistration function for this listener.
|
||||
*/
|
||||
$watch: function(watchExp, listener) {
|
||||
var scope = this;
|
||||
var get = compileToFn(watchExp, 'watch');
|
||||
var listenFn = compileToFn(listener || noop, 'listener');
|
||||
var array = scope.$$watchers;
|
||||
var scope = this,
|
||||
get = compileToFn(watchExp, 'watch'),
|
||||
listenFn = compileToFn(listener || noop, 'listener'),
|
||||
array = scope.$$watchers,
|
||||
watcher = {
|
||||
fn: listenFn,
|
||||
last: Number.NaN, // NaN !== NaN. We used this to force $watch to fire on first run.
|
||||
get: get
|
||||
};
|
||||
|
||||
if (!array) {
|
||||
array = scope.$$watchers = [];
|
||||
}
|
||||
// we use unshift since we use a while loop in $digest for speed.
|
||||
// the while loop reads in reverse order.
|
||||
array.unshift({
|
||||
fn: listenFn,
|
||||
last: Number.NaN, // NaN !== NaN. We used this to force $watch to fire on first run.
|
||||
get: get
|
||||
});
|
||||
array.unshift(watcher);
|
||||
|
||||
return function() {
|
||||
angularArray.remove(array, watcher);
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -538,6 +545,7 @@ Scope.prototype = {
|
|||
*
|
||||
* @param {string} name Event name to listen on.
|
||||
* @param {function(event)} listener Function to call when the event is emitted.
|
||||
* @returns {function()} Returns a deregistration function for this listener.
|
||||
*
|
||||
* The event listener function format is: `function(event)`. The `event` object passed into the
|
||||
* listener has the following attributes
|
||||
|
|
@ -553,29 +561,12 @@ Scope.prototype = {
|
|||
this.$$listeners[name] = namedListeners = [];
|
||||
}
|
||||
namedListeners.push(listener);
|
||||
|
||||
return function() {
|
||||
angularArray.remove(namedListeners, listener);
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* @workInProgress
|
||||
* @ngdoc function
|
||||
* @name angular.scope.$removeListener
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Remove the on listener registered by {@link angular.scope.$on $on}.
|
||||
*
|
||||
* @param {string} name Event name to remove on.
|
||||
* @param {function} listener Function to remove.
|
||||
*/
|
||||
$removeListener: function(name, listener) {
|
||||
var namedListeners = this.$$listeners[name],
|
||||
i;
|
||||
|
||||
if (namedListeners) {
|
||||
i = indexOf(namedListeners, listener);
|
||||
namedListeners.splice(i, 1);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @workInProgress
|
||||
|
|
|
|||
|
|
@ -207,6 +207,7 @@ describe('Scope', function() {
|
|||
expect(log).toEqual('abc');
|
||||
});
|
||||
|
||||
|
||||
it('should repeat watch cycle from the root elemnt', function() {
|
||||
var log = '';
|
||||
var child = root.$new();
|
||||
|
|
@ -269,6 +270,29 @@ describe('Scope', function() {
|
|||
root.$digest();
|
||||
expect(callCount).toEqual(1);
|
||||
});
|
||||
|
||||
|
||||
it('should return a function that allows listeners to be unregistered', function() {
|
||||
var root = angular.scope(),
|
||||
listener = jasmine.createSpy('watch listener'),
|
||||
listenerRemove;
|
||||
|
||||
listenerRemove = root.$watch('foo', listener);
|
||||
root.$digest(); //init
|
||||
expect(listener).toHaveBeenCalled();
|
||||
expect(listenerRemove).toBeDefined();
|
||||
|
||||
listener.reset();
|
||||
root.foo = 'bar';
|
||||
root.$digest(); //triger
|
||||
expect(listener).toHaveBeenCalledOnce();
|
||||
|
||||
listener.reset();
|
||||
root.foo = 'baz';
|
||||
listenerRemove();
|
||||
root.$digest(); //trigger
|
||||
expect(listener).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -434,6 +458,55 @@ describe('Scope', function() {
|
|||
|
||||
describe('events', function() {
|
||||
|
||||
describe('$on', function() {
|
||||
|
||||
it('should add listener for both $emit and $broadcast events', function() {
|
||||
var log = '',
|
||||
root = angular.scope(),
|
||||
child = root.$new();
|
||||
|
||||
function eventFn(){
|
||||
log += 'X';
|
||||
}
|
||||
|
||||
child.$on('abc', eventFn);
|
||||
expect(log).toEqual('');
|
||||
|
||||
child.$emit('abc');
|
||||
expect(log).toEqual('X');
|
||||
|
||||
child.$broadcast('abc');
|
||||
expect(log).toEqual('XX');
|
||||
});
|
||||
|
||||
|
||||
it('should return a function that deregisters the listener', function() {
|
||||
var log = '',
|
||||
root = angular.scope(),
|
||||
child = root.$new(),
|
||||
listenerRemove;
|
||||
|
||||
function eventFn(){
|
||||
log += 'X';
|
||||
}
|
||||
|
||||
listenerRemove = child.$on('abc', eventFn);
|
||||
expect(log).toEqual('');
|
||||
expect(listenerRemove).toBeDefined();
|
||||
|
||||
child.$emit('abc');
|
||||
child.$broadcast('abc');
|
||||
expect(log).toEqual('XX');
|
||||
|
||||
log = '';
|
||||
listenerRemove();
|
||||
child.$emit('abc');
|
||||
child.$broadcast('abc');
|
||||
expect(log).toEqual('');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('$emit', function() {
|
||||
var log, child, grandChild, greatGrandChild;
|
||||
|
||||
|
|
@ -480,21 +553,6 @@ describe('Scope', function() {
|
|||
});
|
||||
|
||||
|
||||
it('should remove event listener', function() {
|
||||
function eventFn(){
|
||||
log += 'abc;';
|
||||
}
|
||||
|
||||
child.$on('abc', eventFn);
|
||||
child.$emit('abc');
|
||||
expect(log).toEqual('abc;');
|
||||
log = '';
|
||||
child.$removeListener('abc', eventFn);
|
||||
child.$emit('abc');
|
||||
expect(log).toEqual('');
|
||||
});
|
||||
|
||||
|
||||
it('should forward method arguments', function() {
|
||||
child.$on('abc', function(event, arg1, arg2){
|
||||
expect(event.name).toBe('abc');
|
||||
|
|
|
|||
Loading…
Reference in a new issue