Skip to content

Commit 3097fc2

Browse files
Created a flag called $skipChildWatchers that has the depth-first traversal of the digest loop skip a scope's children when that flag is true.
1 parent 47a55ca commit 3097fc2

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

src/ng/rootScope.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ function $RootScopeProvider() {
136136
this.$$listeners = {};
137137
this.$$listenerCount = {};
138138
this.$$isolateBindings = null;
139+
this.$skipChildWatchers = false;
139140
}
140141

141142
/**
@@ -162,6 +163,14 @@ function $RootScopeProvider() {
162163
* Reference to the root scope.
163164
*/
164165

166+
/**
167+
* @ngdoc property
168+
* @name $rootScope.Scope#$skipChildWatchers
169+
*
170+
* @description
171+
* If set to true, $digest loop bypasses this scope's children
172+
*/
173+
165174
Scope.prototype = {
166175
constructor: Scope,
167176
/**
@@ -794,7 +803,7 @@ function $RootScopeProvider() {
794803
// Insanity Warning: scope depth-first traversal
795804
// yes, this code is a bit crazy, but it works and we have tests to prove it!
796805
// this piece should be kept in sync with the traversal in $broadcast
797-
if (!(next = (current.$$childHead ||
806+
if (!(next = ((!current.$skipChildWatchers && current.$$childHead) ||
798807
(current !== target && current.$$nextSibling)))) {
799808
while (current !== target && !(next = current.$$nextSibling)) {
800809
current = current.$parent;

test/ng/rootScopeSpec.js

+59
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ describe('Scope', function() {
4949
}));
5050
});
5151

52+
describe('$skipChildWatchers', function() {
53+
it('should initially be false', inject(function($rootScope) {
54+
expect($rootScope.$skipChildWatchers).toBeDefined();
55+
expect($rootScope.$skipChildWatchers).toEqual(false);
56+
}));
57+
});
5258

5359
describe('this', function() {
5460
it('should evaluate \'this\' to be the scope', inject(function($rootScope) {
@@ -458,6 +464,59 @@ describe('Scope', function() {
458464
expect(log).toEqual([]);
459465
}));
460466

467+
it('should $digest scope marked $skipChildWatchers to true, but not its children.',
468+
inject(function ($rootScope) {
469+
var log = '',
470+
parent = $rootScope.$new(),
471+
childA = parent.$new(),
472+
childB = parent.$new();
473+
474+
parent.$watch(function(){ log += 'a';});
475+
childA.$watch(function(){ log += 'b';});
476+
childB.$watch(function(){ log += 'c';});
477+
parent.$skipChildWatchers = true;
478+
479+
$rootScope.$digest();
480+
expect(log).toEqual('aa');
481+
}));
482+
483+
it('should $digest children after parent\'s $skipChildWatchers is set back to false',
484+
inject(function ($rootScope) {
485+
var log = '',
486+
parent = $rootScope.$new(),
487+
childA = parent.$new(),
488+
childB = parent.$new();
489+
490+
parent.$watch(function(){ log+='a'});
491+
childA.$watch('a', function(v){
492+
$rootScope.b = v;
493+
log += 'b'
494+
});
495+
childB.$watch('b', function(v){
496+
$rootScope.c = v;
497+
log += 'c'
498+
});
499+
500+
$rootScope.$digest();
501+
expect(log).toEqual('abca');
502+
503+
log = '';
504+
parent.a = 1;
505+
parent.$skipChildWatchers = true;
506+
507+
$rootScope.$digest();
508+
expect(log).toEqual('a');
509+
expect($rootScope.b).toBeUndefined();
510+
expect($rootScope.c).toBeUndefined();
511+
512+
log = '';
513+
parent.$skipChildWatchers = false;
514+
515+
$rootScope.$digest();
516+
expect(log).toEqual('abca');
517+
expect($rootScope.b).toEqual(1);
518+
expect($rootScope.c).toEqual(1);
519+
}));
461520

462521
describe('$watch deregistration', function() {
463522

0 commit comments

Comments
 (0)