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

Commit d6e3e1b

Browse files
committed
feta(scope): watch object refference or equality
Breaks: Must set $watch equality to true for the old behavior
1 parent ffa8441 commit d6e3e1b

File tree

3 files changed

+46
-26
lines changed

3 files changed

+46
-26
lines changed

src/directives.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ function classDirective(name, selector) {
592592
if (isObject(newVal) && !isArray(newVal))
593593
newVal = map(newVal, function(v, k) { if (v) return k });
594594
if (newVal) element.addClass(isArray(newVal) ? newVal.join(' ') : newVal); }
595-
});
595+
}, true);
596596
});
597597
}
598598

@@ -837,7 +837,7 @@ var ngStyleDirective = valueFn(function(scope, element, attr) {
837837
forEach(oldStyles, function(val, style) { element.css(style, '');});
838838
}
839839
if (newStyles) element.css(newStyles);
840-
});
840+
}, true);
841841
});
842842

843843

src/service/scope.js

+22-6
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@
3535
* event processing life-cycle. See {@link guide/dev_guide.scopes developer guide on scopes}.
3636
*/
3737
function $RootScopeProvider(){
38+
var TTL = 10;
39+
40+
this.ttl = function(value) {
41+
if (arguments.length) {
42+
TTL = value;
43+
}
44+
return TTL;
45+
}
46+
3847
this.$get = ['$injector', '$exceptionHandler', '$parse',
3948
function( $injector, $exceptionHandler, $parse) {
4049

@@ -248,17 +257,20 @@ function $RootScopeProvider(){
248257
*
249258
* - `string`: Evaluated as {@link guide/dev_guide.expressions expression}
250259
* - `function(newValue, oldValue, scope)`: called with current and previous values as parameters.
260+
*
261+
* @param {boolean=} objectEquality Compare object for equality rather then for refference.
251262
* @returns {function()} Returns a deregistration function for this listener.
252263
*/
253-
$watch: function(watchExp, listener) {
264+
$watch: function(watchExp, listener, objectEquality) {
254265
var scope = this,
255266
get = compileToFn(watchExp, 'watch'),
256267
array = scope.$$watchers,
257268
watcher = {
258269
fn: listener,
259270
last: initWatchVal,
260271
get: get,
261-
exp: watchExp
272+
exp: watchExp,
273+
eq: !!objectEquality
262274
};
263275

264276
// in the case user pass string, we need to compile it, do we really need this ?
@@ -332,7 +344,7 @@ function $RootScopeProvider(){
332344
watchers,
333345
asyncQueue,
334346
length,
335-
dirty, ttl = 100,
347+
dirty, ttl = TTL,
336348
next, current, target = this,
337349
watchLog = [],
338350
logIdx, logMsg;
@@ -359,9 +371,13 @@ function $RootScopeProvider(){
359371
watch = watchers[length];
360372
// Most common watches are on primitives, in which case we can short
361373
// circuit it with === operator, only when === fails do we use .equals
362-
if ((value = watch.get(current)) !== (last = watch.last) && !equals(value, last)) {
374+
if ((value = watch.get(current)) !== (last = watch.last) &&
375+
!(watch.eq
376+
? equals(value, last)
377+
: (typeof value == 'number' && typeof last == 'number'
378+
&& isNaN(value) && isNaN(last)))) {
363379
dirty = true;
364-
watch.last = copy(value);
380+
watch.last = watch.eq ? copy(value) : value;
365381
watch.fn(value, ((last === initWatchVal) ? value : last), current);
366382
if (ttl < 5) {
367383
logIdx = 4 - ttl;
@@ -390,7 +406,7 @@ function $RootScopeProvider(){
390406
} while ((current = next));
391407

392408
if(dirty && !(ttl--)) {
393-
throw Error('100 $digest() iterations reached. Aborting!\n' +
409+
throw Error(TTL + ' $digest() iterations reached. Aborting!\n' +
394410
'Watchers fired in the last 5 iterations: ' + toJson(watchLog));
395411
}
396412
} while (dirty || asyncQueue.length);

test/service/scopeSpec.js

+22-18
Original file line numberDiff line numberDiff line change
@@ -189,22 +189,26 @@ describe('Scope', function() {
189189
}));
190190

191191

192-
it('should prevent infinite recursion and print watcher expression',inject(
193-
function($rootScope) {
194-
$rootScope.$watch('a', function() {$rootScope.b++;});
195-
$rootScope.$watch('b', function() {$rootScope.a++;});
196-
$rootScope.a = $rootScope.b = 0;
192+
it('should prevent infinite recursion and print watcher expression',function() {
193+
module(function($rootScopeProvider) {
194+
$rootScopeProvider.ttl(100);
195+
});
196+
inject(function($rootScope) {
197+
$rootScope.$watch('a', function() {$rootScope.b++;});
198+
$rootScope.$watch('b', function() {$rootScope.a++;});
199+
$rootScope.a = $rootScope.b = 0;
197200

198-
expect(function() {
199-
$rootScope.$digest();
200-
}).toThrow('100 $digest() iterations reached. Aborting!\n'+
201-
'Watchers fired in the last 5 iterations: ' +
202-
'[["a; newVal: 96; oldVal: 95","b; newVal: 97; oldVal: 96"],' +
203-
'["a; newVal: 97; oldVal: 96","b; newVal: 98; oldVal: 97"],' +
204-
'["a; newVal: 98; oldVal: 97","b; newVal: 99; oldVal: 98"],' +
205-
'["a; newVal: 99; oldVal: 98","b; newVal: 100; oldVal: 99"],' +
206-
'["a; newVal: 100; oldVal: 99","b; newVal: 101; oldVal: 100"]]');
207-
}));
201+
expect(function() {
202+
$rootScope.$digest();
203+
}).toThrow('100 $digest() iterations reached. Aborting!\n'+
204+
'Watchers fired in the last 5 iterations: ' +
205+
'[["a; newVal: 96; oldVal: 95","b; newVal: 97; oldVal: 96"],' +
206+
'["a; newVal: 97; oldVal: 96","b; newVal: 98; oldVal: 97"],' +
207+
'["a; newVal: 98; oldVal: 97","b; newVal: 99; oldVal: 98"],' +
208+
'["a; newVal: 99; oldVal: 98","b; newVal: 100; oldVal: 99"],' +
209+
'["a; newVal: 100; oldVal: 99","b; newVal: 101; oldVal: 100"]]');
210+
});
211+
});
208212

209213

210214
it('should prevent infinite recursion and print print watcher function name or body',
@@ -241,11 +245,11 @@ describe('Scope', function() {
241245
$rootScope.$watch('a', function(value) {
242246
log +='.';
243247
expect(value).toBe($rootScope.a);
244-
});
248+
}, true);
245249
$rootScope.$watch('b', function(value) {
246250
log +='!';
247251
expect(value).toBe($rootScope.b);
248-
});
252+
}, true);
249253
$rootScope.$digest();
250254
log = '';
251255

@@ -331,7 +335,7 @@ describe('Scope', function() {
331335
$rootScope.$watch(function() { return undefined;}, logger);
332336
$rootScope.$watch(function() { return '';}, logger);
333337
$rootScope.$watch(function() { return false;}, logger);
334-
$rootScope.$watch(function() { return {};}, logger);
338+
$rootScope.$watch(function() { return {};}, logger, true);
335339
$rootScope.$watch(function() { return 23;}, logger);
336340

337341
$rootScope.$digest();

0 commit comments

Comments
 (0)