diff options
| -rw-r--r-- | src/directives.js | 4 | ||||
| -rw-r--r-- | src/service/scope.js | 28 | ||||
| -rw-r--r-- | test/service/scopeSpec.js | 40 | 
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();  | 
