aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMisko Hevery2012-02-23 15:01:08 -0800
committerMisko Hevery2012-02-23 15:01:08 -0800
commitd6e3e1baabc3acc930e4fda387b62cbd03e64577 (patch)
treee17ba1673d9d78e4bc71364966ef607fdbc42434
parentffa84418862a9f768ce5b9b681916438f14a0d79 (diff)
downloadangular.js-d6e3e1baabc3acc930e4fda387b62cbd03e64577.tar.bz2
feta(scope): watch object refference or equality
Breaks: Must set $watch equality to true for the old behavior
-rw-r--r--src/directives.js4
-rw-r--r--src/service/scope.js28
-rw-r--r--test/service/scopeSpec.js40
3 files changed, 46 insertions, 26 deletions
diff --git a/src/directives.js b/src/directives.js
index 67c9f1f6..8a2af704 100644
--- a/src/directives.js
+++ b/src/directives.js
@@ -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);
});
}
@@ -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);
});
diff --git a/src/service/scope.js b/src/service/scope.js
index 2d2f7fec..79708f0c 100644
--- a/src/service/scope.js
+++ b/src/service/scope.js
@@ -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) {
@@ -248,9 +257,11 @@ 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,
@@ -258,7 +269,8 @@ function $RootScopeProvider(){
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 ?
@@ -332,7 +344,7 @@ function $RootScopeProvider(){
watchers,
asyncQueue,
length,
- dirty, ttl = 100,
+ dirty, ttl = TTL,
next, current, target = this,
watchLog = [],
logIdx, logMsg;
@@ -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;
@@ -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);
diff --git a/test/service/scopeSpec.js b/test/service/scopeSpec.js
index 179ff162..c4940931 100644
--- a/test/service/scopeSpec.js
+++ b/test/service/scopeSpec.js
@@ -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',
@@ -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 = '';
@@ -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();