mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
fix(Scope): allow removing a listener during event
This commit is contained in:
parent
682418f029
commit
e6966e05f5
2 changed files with 91 additions and 5 deletions
|
|
@ -638,7 +638,7 @@ function $RootScopeProvider(){
|
|||
namedListeners.push(listener);
|
||||
|
||||
return function() {
|
||||
arrayRemove(namedListeners, listener);
|
||||
namedListeners[indexOf(namedListeners, listener)] = null;
|
||||
};
|
||||
},
|
||||
|
||||
|
|
@ -686,6 +686,14 @@ function $RootScopeProvider(){
|
|||
namedListeners = scope.$$listeners[name] || empty;
|
||||
event.currentScope = scope;
|
||||
for (i=0, length=namedListeners.length; i<length; i++) {
|
||||
|
||||
// if listeners were deregistered, defragment the array
|
||||
if (!namedListeners[i]) {
|
||||
namedListeners.splice(i, 1);
|
||||
i--;
|
||||
length--;
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
namedListeners[i].apply(null, listenerArgs);
|
||||
if (stopPropagation) return event;
|
||||
|
|
@ -735,19 +743,29 @@ function $RootScopeProvider(){
|
|||
},
|
||||
defaultPrevented: false
|
||||
},
|
||||
listenerArgs = concat([event], arguments, 1);
|
||||
listenerArgs = concat([event], arguments, 1),
|
||||
listeners, i, length;
|
||||
|
||||
//down while you can, then up and next sibling or up and next sibling until back at root
|
||||
do {
|
||||
current = next;
|
||||
event.currentScope = current;
|
||||
forEach(current.$$listeners[name], function(listener) {
|
||||
listeners = current.$$listeners[name] || [];
|
||||
for (i=0, length = listeners.length; i<length; i++) {
|
||||
// if listeners were deregistered, defragment the array
|
||||
if (!listeners[i]) {
|
||||
listeners.splice(i, 1);
|
||||
i--;
|
||||
length--;
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
listener.apply(null, listenerArgs);
|
||||
listeners[i].apply(null, listenerArgs);
|
||||
} catch(e) {
|
||||
$exceptionHandler(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Insanity Warning: scope depth-first traversal
|
||||
// yes, this code is a bit crazy, but it works and we have tests to prove it!
|
||||
|
|
|
|||
|
|
@ -708,6 +708,74 @@ describe('Scope', function() {
|
|||
});
|
||||
|
||||
|
||||
it('should allow removing event listener inside a listener on $emit', function() {
|
||||
var spy1 = jasmine.createSpy('1st listener');
|
||||
var spy2 = jasmine.createSpy('2nd listener');
|
||||
var spy3 = jasmine.createSpy('3rd listener');
|
||||
|
||||
var remove1 = child.$on('evt', spy1);
|
||||
var remove2 = child.$on('evt', spy2);
|
||||
var remove3 = child.$on('evt', spy3);
|
||||
|
||||
spy1.andCallFake(remove1);
|
||||
|
||||
expect(child.$$listeners['evt'].length).toBe(3);
|
||||
|
||||
// should call all listeners and remove 1st
|
||||
child.$emit('evt');
|
||||
expect(spy1).toHaveBeenCalledOnce();
|
||||
expect(spy2).toHaveBeenCalledOnce();
|
||||
expect(spy3).toHaveBeenCalledOnce();
|
||||
expect(child.$$listeners['evt'].length).toBe(3); // cleanup will happen on next $emit
|
||||
|
||||
spy1.reset();
|
||||
spy2.reset();
|
||||
spy3.reset();
|
||||
|
||||
// should call only 2nd because 1st was already removed and 2nd removes 3rd
|
||||
spy2.andCallFake(remove3);
|
||||
child.$emit('evt');
|
||||
expect(spy1).not.toHaveBeenCalled();
|
||||
expect(spy2).toHaveBeenCalledOnce();
|
||||
expect(spy3).not.toHaveBeenCalled();
|
||||
expect(child.$$listeners['evt'].length).toBe(1);
|
||||
});
|
||||
|
||||
|
||||
it('should allow removing event listener inside a listener on $broadcast', function() {
|
||||
var spy1 = jasmine.createSpy('1st listener');
|
||||
var spy2 = jasmine.createSpy('2nd listener');
|
||||
var spy3 = jasmine.createSpy('3rd listener');
|
||||
|
||||
var remove1 = child.$on('evt', spy1);
|
||||
var remove2 = child.$on('evt', spy2);
|
||||
var remove3 = child.$on('evt', spy3);
|
||||
|
||||
spy1.andCallFake(remove1);
|
||||
|
||||
expect(child.$$listeners['evt'].length).toBe(3);
|
||||
|
||||
// should call all listeners and remove 1st
|
||||
child.$broadcast('evt');
|
||||
expect(spy1).toHaveBeenCalledOnce();
|
||||
expect(spy2).toHaveBeenCalledOnce();
|
||||
expect(spy3).toHaveBeenCalledOnce();
|
||||
expect(child.$$listeners['evt'].length).toBe(3); //cleanup will happen on next $broadcast
|
||||
|
||||
spy1.reset();
|
||||
spy2.reset();
|
||||
spy3.reset();
|
||||
|
||||
// should call only 2nd because 1st was already removed and 2nd removes 3rd
|
||||
spy2.andCallFake(remove3);
|
||||
child.$broadcast('evt');
|
||||
expect(spy1).not.toHaveBeenCalled();
|
||||
expect(spy2).toHaveBeenCalledOnce();
|
||||
expect(spy3).not.toHaveBeenCalled();
|
||||
expect(child.$$listeners['evt'].length).toBe(1);
|
||||
});
|
||||
|
||||
|
||||
describe('event object', function() {
|
||||
it('should have methods/properties', function() {
|
||||
var event;
|
||||
|
|
|
|||
Loading…
Reference in a new issue