From 71fe0b4ddf8f9650315b0c05d03893354ec9bba9 Mon Sep 17 00:00:00 2001 From: joshrtay Date: Wed, 26 Dec 2012 16:20:23 -0800 Subject: [PATCH] feat($rootScope): stopDescent method added to broadcast event stopDescent method stops $broadcast-ed events from propagating to children. --- src/ng/rootScope.js | 9 ++++++++- test/ng/rootScopeSpec.js | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js index c99416f0040d..e303e750b518 100644 --- a/src/ng/rootScope.js +++ b/src/ng/rootScope.js @@ -630,6 +630,9 @@ function $RootScopeProvider(){ * - `name` - `{string}`: Name of the event. * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel further event * propagation (available only for events that were `$emit`-ed). + * - `stopDescent` - `{function=}`: calling `stopDescent` function will cancel further event + * propagation to listeners on scope and children scope. events will continue to propogate to + * sibling scopes and their children (available only for events that were `$broadcast`-ed). * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true. * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called. */ @@ -738,9 +741,11 @@ function $RootScopeProvider(){ var target = this, current = target, next = target, + stopDescent = false, event = { name: name, targetScope: target, + stopDescent: function() {stopDescent = true;}, preventDefault: function() { event.defaultPrevented = true; }, @@ -751,6 +756,7 @@ function $RootScopeProvider(){ //down while you can, then up and next sibling or up and next sibling until back at root do { + stopDescent = false; current = next; event.currentScope = current; listeners = current.$$listeners[name] || []; @@ -765,6 +771,7 @@ function $RootScopeProvider(){ try { listeners[i].apply(null, listenerArgs); + if (stopDescent) break; } catch(e) { $exceptionHandler(e); } @@ -773,7 +780,7 @@ function $RootScopeProvider(){ // Insanity Warning: scope depth-first traversal // yes, this code is a bit crazy, but it works and we have tests to prove it! // this piece should be kept in sync with the traversal in $digest - if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) { + if (!(next = ( ( !stopDescent && current.$$childHead) || (current !== target && current.$$nextSibling)))) { while(current !== target && !(next = current.$$nextSibling)) { current = current.$parent; } diff --git a/test/ng/rootScopeSpec.js b/test/ng/rootScopeSpec.js index 55fc41b1db81..5e400bfc8193 100644 --- a/test/ng/rootScopeSpec.js +++ b/test/ng/rootScopeSpec.js @@ -907,6 +907,24 @@ describe('Scope', function() { expect(result.name).toBe('some'); expect(result.targetScope).toBe(child1); }); + + it('should allow stopping event descent from root scope', inject(function($rootScope) { + child2.$on('myEvent', function(event) { event.stopDescent(); }); + $rootScope.$broadcast('myEvent'); + expect(log).toEqual('0>1>11>2>3>'); + })); + + it('should allow stopping event descent from child scope', function() { + grandChild21.$on('myEvent', function(event) { event.stopDescent(); }); + child2.$broadcast('myEvent'); + expect(log).toEqual('2>21>22>23>'); + }); + + it('should not stop descent on sibling scopes', inject(function($rootScope) { + child1.$on('myEvent', function(event) { event.stopDescent(); }); + $rootScope.$broadcast('myEvent'); + expect(log).toEqual('0>1>2>21>211>22>23>3>'); + })); });