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

Commit

Permalink
feta(scope): watch object refference or equality
Browse files Browse the repository at this point in the history
Breaks: Must set $watch equality to true for the old behavior
  • Loading branch information
mhevery committed Feb 23, 2012
1 parent ffa8441 commit d6e3e1b
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 26 deletions.
4 changes: 2 additions & 2 deletions src/directives.js
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ function classDirective(name, selector) {
if (isObject(newVal) && !isArray(newVal))
newVal = map(newVal, function(v, k) { if (v) return k });
if (newVal) element.addClass(isArray(newVal) ? newVal.join(' ') : newVal); }
});
}, true);
});
}

Expand Down Expand Up @@ -837,7 +837,7 @@ var ngStyleDirective = valueFn(function(scope, element, attr) {
forEach(oldStyles, function(val, style) { element.css(style, '');});
}
if (newStyles) element.css(newStyles);
});
}, true);
});


Expand Down
28 changes: 22 additions & 6 deletions src/service/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@
* event processing life-cycle. See {@link guide/dev_guide.scopes developer guide on scopes}.
*/
function $RootScopeProvider(){
var TTL = 10;

this.ttl = function(value) {
if (arguments.length) {
TTL = value;
}
return TTL;
}

this.$get = ['$injector', '$exceptionHandler', '$parse',
function( $injector, $exceptionHandler, $parse) {

Expand Down Expand Up @@ -248,17 +257,20 @@ function $RootScopeProvider(){
*
* - `string`: Evaluated as {@link guide/dev_guide.expressions expression}
* - `function(newValue, oldValue, scope)`: called with current and previous values as parameters.
*
* @param {boolean=} objectEquality Compare object for equality rather then for refference.
* @returns {function()} Returns a deregistration function for this listener.
*/
$watch: function(watchExp, listener) {
$watch: function(watchExp, listener, objectEquality) {
var scope = this,
get = compileToFn(watchExp, 'watch'),
array = scope.$$watchers,
watcher = {
fn: listener,
last: initWatchVal,
get: get,
exp: watchExp
exp: watchExp,
eq: !!objectEquality
};

// in the case user pass string, we need to compile it, do we really need this ?
Expand Down Expand Up @@ -332,7 +344,7 @@ function $RootScopeProvider(){
watchers,
asyncQueue,
length,
dirty, ttl = 100,
dirty, ttl = TTL,
next, current, target = this,
watchLog = [],
logIdx, logMsg;
Expand All @@ -359,9 +371,13 @@ function $RootScopeProvider(){
watch = watchers[length];
// Most common watches are on primitives, in which case we can short
// circuit it with === operator, only when === fails do we use .equals
if ((value = watch.get(current)) !== (last = watch.last) && !equals(value, last)) {
if ((value = watch.get(current)) !== (last = watch.last) &&
!(watch.eq
? equals(value, last)
: (typeof value == 'number' && typeof last == 'number'
&& isNaN(value) && isNaN(last)))) {
dirty = true;
watch.last = copy(value);
watch.last = watch.eq ? copy(value) : value;
watch.fn(value, ((last === initWatchVal) ? value : last), current);
if (ttl < 5) {
logIdx = 4 - ttl;
Expand Down Expand Up @@ -390,7 +406,7 @@ function $RootScopeProvider(){
} while ((current = next));

if(dirty && !(ttl--)) {
throw Error('100 $digest() iterations reached. Aborting!\n' +
throw Error(TTL + ' $digest() iterations reached. Aborting!\n' +
'Watchers fired in the last 5 iterations: ' + toJson(watchLog));
}
} while (dirty || asyncQueue.length);
Expand Down
40 changes: 22 additions & 18 deletions test/service/scopeSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,22 +189,26 @@ describe('Scope', function() {
}));


it('should prevent infinite recursion and print watcher expression',inject(
function($rootScope) {
$rootScope.$watch('a', function() {$rootScope.b++;});
$rootScope.$watch('b', function() {$rootScope.a++;});
$rootScope.a = $rootScope.b = 0;
it('should prevent infinite recursion and print watcher expression',function() {
module(function($rootScopeProvider) {
$rootScopeProvider.ttl(100);
});
inject(function($rootScope) {
$rootScope.$watch('a', function() {$rootScope.b++;});
$rootScope.$watch('b', function() {$rootScope.a++;});
$rootScope.a = $rootScope.b = 0;

expect(function() {
$rootScope.$digest();
}).toThrow('100 $digest() iterations reached. Aborting!\n'+
'Watchers fired in the last 5 iterations: ' +
'[["a; newVal: 96; oldVal: 95","b; newVal: 97; oldVal: 96"],' +
'["a; newVal: 97; oldVal: 96","b; newVal: 98; oldVal: 97"],' +
'["a; newVal: 98; oldVal: 97","b; newVal: 99; oldVal: 98"],' +
'["a; newVal: 99; oldVal: 98","b; newVal: 100; oldVal: 99"],' +
'["a; newVal: 100; oldVal: 99","b; newVal: 101; oldVal: 100"]]');
}));
expect(function() {
$rootScope.$digest();
}).toThrow('100 $digest() iterations reached. Aborting!\n'+
'Watchers fired in the last 5 iterations: ' +
'[["a; newVal: 96; oldVal: 95","b; newVal: 97; oldVal: 96"],' +
'["a; newVal: 97; oldVal: 96","b; newVal: 98; oldVal: 97"],' +
'["a; newVal: 98; oldVal: 97","b; newVal: 99; oldVal: 98"],' +
'["a; newVal: 99; oldVal: 98","b; newVal: 100; oldVal: 99"],' +
'["a; newVal: 100; oldVal: 99","b; newVal: 101; oldVal: 100"]]');
});
});


it('should prevent infinite recursion and print print watcher function name or body',
Expand Down Expand Up @@ -241,11 +245,11 @@ describe('Scope', function() {
$rootScope.$watch('a', function(value) {
log +='.';
expect(value).toBe($rootScope.a);
});
}, true);
$rootScope.$watch('b', function(value) {
log +='!';
expect(value).toBe($rootScope.b);
});
}, true);
$rootScope.$digest();
log = '';

Expand Down Expand Up @@ -331,7 +335,7 @@ describe('Scope', function() {
$rootScope.$watch(function() { return undefined;}, logger);
$rootScope.$watch(function() { return '';}, logger);
$rootScope.$watch(function() { return false;}, logger);
$rootScope.$watch(function() { return {};}, logger);
$rootScope.$watch(function() { return {};}, logger, true);
$rootScope.$watch(function() { return 23;}, logger);

$rootScope.$digest();
Expand Down

0 comments on commit d6e3e1b

Please sign in to comment.