From be98f7c2f069103683a8aab60d794007db7d9bc2 Mon Sep 17 00:00:00 2001 From: rodyhaddad Date: Mon, 2 Jun 2014 10:17:36 -0700 Subject: [PATCH] revert: feat(*): lazy one-time binding support This reverts commit cee429f0aaebf32ef1c9aedd8447a48f163dd0a4. See #7700 for a more performant approach for bind-once. --- docs/content/guide/expression.ngdoc | 119 ---------------------------- src/ng/compile.js | 4 - src/ng/directive/ngBind.js | 6 +- src/ng/interpolate.js | 3 - src/ng/parse.js | 41 +--------- src/ng/rootScope.js | 35 +++----- src/ng/sce.js | 4 +- test/ng/compileSpec.js | 110 ------------------------- test/ng/directive/ngBindSpec.js | 65 --------------- test/ng/directive/ngRepeatSpec.js | 36 --------- test/ng/parseSpec.js | 75 ------------------ test/ng/rootScopeSpec.js | 49 ------------ test/ng/sceSpecs.js | 9 --- 13 files changed, 15 insertions(+), 541 deletions(-) diff --git a/docs/content/guide/expression.ngdoc b/docs/content/guide/expression.ngdoc index 907a021025bc..dbae3326e904 100644 --- a/docs/content/guide/expression.ngdoc +++ b/docs/content/guide/expression.ngdoc @@ -200,122 +200,3 @@ expose a `$event` object within the scope of that expression. Note in the example above how we can pass in `$event` to `clickMe`, but how it does not show up in `{{$event}}`. This is because `$event` is outside the scope of that binding. - - -## One-time binding - -An expression that starts with `::` is considered a one-time expression. One-time expressions -will stop recalculating once they are stable, which happens after the first digest if the expression -result is a non-undefined value (see value stabilization algorithm below). - - - -
- -

One time binding: {{::name}}

-

Normal binding: {{name}}

-
-
- - angular.module('oneTimeBidingExampleApp', []). - controller('EventController', ['$scope', function($scope) { - var counter = 0; - var names = ['Igor', 'Misko', 'Chirayu', 'Lucas']; - /* - * expose the event object to the scope - */ - $scope.clickMe = function(clickEvent) { - $scope.name = names[counter % names.length]; - counter++; - }; - }]); - - - it('should freeze binding after its value has stabilized', function() { - var oneTimeBiding = element(by.id('one-time-binding-example')); - var normalBinding = element(by.id('normal-binding-example')); - - expect(oneTimeBiding.getText()).toEqual('One time binding:'); - expect(normalBinding.getText()).toEqual('Normal binding:'); - element(by.buttonText('Click Me')).click(); - - expect(oneTimeBiding.getText()).toEqual('One time binding: Igor'); - expect(normalBinding.getText()).toEqual('Normal binding: Igor'); - element(by.buttonText('Click Me')).click(); - - expect(oneTimeBiding.getText()).toEqual('One time binding: Igor'); - expect(normalBinding.getText()).toEqual('Normal binding: Misko'); - - element(by.buttonText('Click Me')).click(); - element(by.buttonText('Click Me')).click(); - - expect(oneTimeBiding.getText()).toEqual('One time binding: Igor'); - expect(normalBinding.getText()).toEqual('Normal binding: Lucas'); - }); - -
- - -### Why this feature - -The main purpose of one-time binding expression is to provide a way to create a binding -that gets deregistered and frees up resources once the binding is stabilized. -Reducing the number of expressions being watched makes the digest loop faster and allows more -information to be displayed at the same time. - - -### Value stabilization algorithm - -One-time binding expressions will retain the value of the expression at the end of the -digest cycle as long as that value is not undefined. If the value of the expression is set -within the digest loop and later, within the same digest loop, it is set to undefined, -then the expression is not fulfilled and will remain watched. - - 1. Given an expression that starts with `::` when a digest loop is entered and expression - is dirty-checked store the value as V - 2. If V is not undefined mark the result of the expression as stable and schedule a task - to deregister the watch for this expression when we exit the digest loop - 3. Process the digest loop as normal - 4. When digest loop is done and all the values have settled process the queue of watch - deregistration tasks. For each watch to be deregistered check if it still evaluates - to value that is not `undefined`. If that's the case, deregister the watch. Otherwise - keep dirty-checking the watch in the future digest loops by following the same - algorithm starting from step 1 - - -### How to benefit from one-time binding - -When interpolating text or attributes. If the expression, once set, will not change -then it is a candidate for one-time expression. - -```html -
text: {{::name}}
-``` - -When using a directive with bidirectional binding and the parameters will not change - -```js -someModule.directive('someDirective', function() { - return { - scope: { - name: '=', - color: '@' - }, - template: '{{name}}: {{color}}' - }; -}); -``` - -```html -
-``` - - -When using a directive that takes an expression - -```html - -``` - diff --git a/src/ng/compile.js b/src/ng/compile.js index bdbd904bcf3e..279ffdc3d239 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -1515,7 +1515,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { parentSet(scope, parentValue = isolateScope[scopeName]); } } - parentValueWatch.$$unwatch = parentGet.$$unwatch; return lastValue = parentValue; }, null, parentGet.literal); break; @@ -1853,9 +1852,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { return function textInterpolateLinkFn(scope, node) { var parent = node.parent(), bindings = parent.data('$binding') || []; - // Need to interpolate again in case this is using one-time bindings in multiple clones - // of transcluded templates. - interpolateFn = $interpolate(text); bindings.push(interpolateFn); parent.data('$binding', bindings); if (!hasCompileParent) safeAddClass(parent, 'ng-binding'); diff --git a/src/ng/directive/ngBind.js b/src/ng/directive/ngBind.js index b854ba75e09b..b95bdd9ccc00 100644 --- a/src/ng/directive/ngBind.js +++ b/src/ng/directive/ngBind.js @@ -179,11 +179,7 @@ var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) { element.addClass('ng-binding').data('$binding', attr.ngBindHtml); var parsed = $parse(attr.ngBindHtml); - function getStringValue() { - var value = parsed(scope); - getStringValue.$$unwatch = parsed.$$unwatch; - return (value || '').toString(); - } + function getStringValue() { return (parsed(scope) || '').toString(); } scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) { element.html($sce.getTrustedHtml(parsed(scope)) || ''); diff --git a/src/ng/interpolate.js b/src/ng/interpolate.js index 830c548277c2..fac06e644af8 100644 --- a/src/ng/interpolate.js +++ b/src/ng/interpolate.js @@ -309,11 +309,9 @@ function $InterpolateProvider() { try { - interpolationFn.$$unwatch = true; for (; i < ii; i++) { val = getValue(parseFns[i](context)); if (allOrNothing && isUndefined(val)) { - interpolationFn.$$unwatch = undefined; return; } val = stringify(val); @@ -321,7 +319,6 @@ function $InterpolateProvider() { inputsChanged = true; } values[i] = val; - interpolationFn.$$unwatch = interpolationFn.$$unwatch && parseFns[i].$$unwatch; } if (inputsChanged) { diff --git a/src/ng/parse.js b/src/ng/parse.js index dbb6b80e5066..0770ae7d9869 100644 --- a/src/ng/parse.js +++ b/src/ng/parse.js @@ -1021,21 +1021,13 @@ function $ParseProvider() { $parseOptions.csp = $sniffer.csp; return function(exp) { - var parsedExpression, - oneTime; + var parsedExpression; switch (typeof exp) { case 'string': - exp = trim(exp); - - if (exp.charAt(0) === ':' && exp.charAt(1) === ':') { - oneTime = true; - exp = exp.substring(2); - } - if (cache.hasOwnProperty(exp)) { - return oneTime ? oneTimeWrapper(cache[exp]) : cache[exp]; + return cache[exp]; } var lexer = new Lexer($parseOptions); @@ -1048,7 +1040,7 @@ function $ParseProvider() { cache[exp] = parsedExpression; } - return oneTime || parsedExpression.constant ? oneTimeWrapper(parsedExpression) : parsedExpression; + return parsedExpression; case 'function': return exp; @@ -1056,32 +1048,5 @@ function $ParseProvider() { default: return noop; } - - function oneTimeWrapper(expression) { - var stable = false, - lastValue; - oneTimeParseFn.literal = expression.literal; - oneTimeParseFn.constant = expression.constant; - oneTimeParseFn.assign = expression.assign; - return oneTimeParseFn; - - function oneTimeParseFn(self, locals) { - if (!stable) { - lastValue = expression.constant && lastValue ? lastValue : expression(self, locals); - oneTimeParseFn.$$unwatch = isDefined(lastValue); - if (oneTimeParseFn.$$unwatch && self && self.$$postDigestQueue) { - self.$$postDigestQueue.push(function () { - // create a copy if the value is defined and it is not a $sce value - if ((stable = isDefined(lastValue)) && - (lastValue === null || !lastValue.$$unwrapTrustedValue)) { - lastValue = copy(lastValue, null); - } - }); - } - } - return lastValue; - } - } - }; }]; } diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js index 34f1fa6ada1a..ab3e12bcb9f9 100644 --- a/src/ng/rootScope.js +++ b/src/ng/rootScope.js @@ -346,6 +346,14 @@ function $RootScopeProvider(){ watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);}; } + if (typeof watchExp == 'string' && get.constant) { + var originalFn = watcher.fn; + watcher.fn = function(newVal, oldVal, scope) { + originalFn.call(this, newVal, oldVal, scope); + arrayRemove(array, watcher); + }; + } + if (!array) { array = scope.$$watchers = []; } @@ -391,28 +399,17 @@ function $RootScopeProvider(){ var deregisterFns = []; var changeCount = 0; var self = this; - var unwatchFlags = new Array(watchExpressions.length); - var unwatchCount = watchExpressions.length; forEach(watchExpressions, function (expr, i) { - var exprFn = $parse(expr); - deregisterFns.push(self.$watch(exprFn, function (value, oldValue) { + deregisterFns.push(self.$watch(expr, function (value, oldValue) { newValues[i] = value; oldValues[i] = oldValue; changeCount++; - if (unwatchFlags[i] && !exprFn.$$unwatch) unwatchCount++; - if (!unwatchFlags[i] && exprFn.$$unwatch) unwatchCount--; - unwatchFlags[i] = exprFn.$$unwatch; })); }, this); - deregisterFns.push(self.$watch(watchGroupFn, function () { + deregisterFns.push(self.$watch(function () {return changeCount;}, function () { listener(newValues, oldValues, self); - if (unwatchCount === 0) { - watchGroupFn.$$unwatch = true; - } else { - watchGroupFn.$$unwatch = false; - } })); return function deregisterWatchGroup() { @@ -420,8 +417,6 @@ function $RootScopeProvider(){ fn(); }); }; - - function watchGroupFn() {return changeCount;} }, @@ -566,7 +561,6 @@ function $RootScopeProvider(){ } } } - $watchCollectionWatch.$$unwatch = objGetter.$$unwatch; return changeDetected; } @@ -662,7 +656,6 @@ function $RootScopeProvider(){ dirty, ttl = TTL, next, current, target = this, watchLog = [], - stableWatchesCandidates = [], logIdx, logMsg, asyncTask; beginPhase('$digest'); @@ -713,7 +706,6 @@ function $RootScopeProvider(){ logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last); watchLog[logIdx].push(logMsg); } - if (watch.get.$$unwatch) stableWatchesCandidates.push({watch: watch, array: watchers}); } else if (watch === lastDirtyWatch) { // If the most recently dirty watcher is now clean, short circuit since the remaining watchers // have already been tested. @@ -760,13 +752,6 @@ function $RootScopeProvider(){ $exceptionHandler(e); } } - - for (length = stableWatchesCandidates.length - 1; length >= 0; --length) { - var candidate = stableWatchesCandidates[length]; - if (candidate.watch.get.$$unwatch) { - arrayRemove(candidate.array, candidate.watch); - } - } }, diff --git a/src/ng/sce.js b/src/ng/sce.js index d3553bde7c45..b51f8764156d 100644 --- a/src/ng/sce.js +++ b/src/ng/sce.js @@ -787,9 +787,7 @@ function $SceProvider() { return parsed; } else { return function sceParseAsTrusted(self, locals) { - var result = sce.getTrusted(type, parsed(self, locals)); - sceParseAsTrusted.$$unwatch = parsed.$$unwatch; - return result; + return sce.getTrusted(type, parsed(self, locals)); }; } }; diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index b0de0f63a831..e7b0dffa310c 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -2201,39 +2201,6 @@ describe('$compile', function() { ); - it('should one-time bind if the expression starts with two colons', inject( - function($rootScope, $compile) { - $rootScope.name = 'angular'; - element = $compile('
text: {{::name}}
')($rootScope); - expect($rootScope.$$watchers.length).toBe(2); - $rootScope.$digest(); - expect(element.text()).toEqual('text: angular'); - expect(element.attr('name')).toEqual('attr: angular'); - expect($rootScope.$$watchers.length).toBe(0); - $rootScope.name = 'not-angular'; - $rootScope.$digest(); - expect(element.text()).toEqual('text: angular'); - expect(element.attr('name')).toEqual('attr: angular'); - }) - ); - - it('should one-time bind if the expression starts with a space and two colons', inject( - function($rootScope, $compile) { - $rootScope.name = 'angular'; - element = $compile('
text: {{ ::name }}
')($rootScope); - expect($rootScope.$$watchers.length).toBe(2); - $rootScope.$digest(); - expect(element.text()).toEqual('text: angular'); - expect(element.attr('name')).toEqual('attr: angular'); - expect($rootScope.$$watchers.length).toBe(0); - $rootScope.name = 'not-angular'; - $rootScope.$digest(); - expect(element.text()).toEqual('text: angular'); - expect(element.attr('name')).toEqual('attr: angular'); - }) - ); - - it('should process attribute interpolation in pre-linking phase at priority 100', function() { module(function() { directive('attrLog', function(log) { @@ -2846,83 +2813,6 @@ describe('$compile', function() { }); - it('should be possible to one-time bind a parameter on a component with a template', function() { - module(function() { - directive('otherTplDir', function() { - return { - scope: {param: '@', anotherParam: '=' }, - template: 'value: {{param}}, another value {{anotherParam}}' - }; - }); - }); - - function countWatches(scope) { - var result = 0; - while (scope !== null) { - result += (scope.$$watchers && scope.$$watchers.length) || 0; - result += countWatches(scope.$$childHead); - scope = scope.$$nextSibling; - } - return result; - } - - inject(function($rootScope) { - compile('
'); - expect(countWatches($rootScope)).toEqual(3); - $rootScope.$digest(); - expect(element.html()).toBe('value: , another value '); - expect(countWatches($rootScope)).toEqual(3); - - $rootScope.foo = 'from-parent'; - $rootScope.$digest(); - expect(element.html()).toBe('value: from-parent, another value '); - expect(countWatches($rootScope)).toEqual(2); - - $rootScope.foo = 'not-from-parent'; - $rootScope.bar = 'some value'; - $rootScope.$digest(); - expect(element.html()).toBe('value: from-parent, another value some value'); - expect(countWatches($rootScope)).toEqual(1); - - $rootScope.bar = 'some new value'; - $rootScope.$digest(); - expect(element.html()).toBe('value: from-parent, another value some value'); - }); - }); - - - it('should be possible to one-time bind a parameter on a component with a templateUrl', function() { - module(function() { - directive('otherTplDir', function() { - return { - scope: {param: '@', anotherParam: '=' }, - templateUrl: 'other.html' - }; - }); - }); - - inject(function($rootScope, $templateCache) { - $templateCache.put('other.html', 'value: {{param}}, another value {{anotherParam}}'); - compile('
'); - $rootScope.$digest(); - expect(element.html()).toBe('value: , another value '); - - $rootScope.foo = 'from-parent'; - $rootScope.$digest(); - expect(element.html()).toBe('value: from-parent, another value '); - - $rootScope.foo = 'not-from-parent'; - $rootScope.bar = 'some value'; - $rootScope.$digest(); - expect(element.html()).toBe('value: from-parent, another value some value'); - - $rootScope.bar = 'some new value'; - $rootScope.$digest(); - expect(element.html()).toBe('value: from-parent, another value some value'); - }); - }); - - describe('attribute', function() { it('should copy simple attribute', inject(function() { compile('
'); diff --git a/test/ng/directive/ngBindSpec.js b/test/ng/directive/ngBindSpec.js index 0029da5fec16..7af4c13f2b63 100644 --- a/test/ng/directive/ngBindSpec.js +++ b/test/ng/directive/ngBindSpec.js @@ -45,43 +45,6 @@ describe('ngBind*', function() { $rootScope.$digest(); expect(element.text()).toEqual('-0false'); })); - - it('should one-time bind if the expression starts with two colons', inject(function($rootScope, $compile) { - element = $compile('
')($rootScope); - $rootScope.a = 'lucas'; - expect($rootScope.$$watchers.length).toEqual(1); - $rootScope.$digest(); - expect(element.text()).toEqual('lucas'); - expect($rootScope.$$watchers.length).toEqual(0); - $rootScope.a = undefined; - $rootScope.$digest(); - expect(element.text()).toEqual('lucas'); - })); - - it('should be possible to bind to a new value within the same $digest', inject(function($rootScope, $compile) { - element = $compile('
')($rootScope); - $rootScope.$watch('a', function(newVal) { if (newVal === 'foo') { $rootScope.a = 'bar'; } }); - $rootScope.a = 'foo'; - $rootScope.$digest(); - expect(element.text()).toEqual('bar'); - $rootScope.a = undefined; - $rootScope.$digest(); - expect(element.text()).toEqual('bar'); - })); - - it('should remove the binding if the value is defined at the end of a $digest loop', inject(function($rootScope, $compile) { - element = $compile('
')($rootScope); - $rootScope.$watch('a', function(newVal) { if (newVal === 'foo') { $rootScope.a = undefined; } }); - $rootScope.a = 'foo'; - $rootScope.$digest(); - expect(element.text()).toEqual(''); - $rootScope.a = 'bar'; - $rootScope.$digest(); - expect(element.text()).toEqual('bar'); - $rootScope.a = 'man'; - $rootScope.$digest(); - expect(element.text()).toEqual('bar'); - })); }); @@ -96,22 +59,6 @@ describe('ngBind*', function() { })); - it('should one-time bind the expressions that start with ::', inject(function($rootScope, $compile) { - element = $compile('
')($rootScope); - $rootScope.name = 'Misko'; - expect($rootScope.$$watchers.length).toEqual(1); - $rootScope.$digest(); - expect(element.hasClass('ng-binding')).toEqual(true); - expect(element.text()).toEqual(' Misko!'); - expect($rootScope.$$watchers.length).toEqual(1); - $rootScope.hello = 'Hello'; - $rootScope.name = 'Lucas'; - $rootScope.$digest(); - expect(element.text()).toEqual('Hello Misko!'); - expect($rootScope.$$watchers.length).toEqual(0); - })); - - it('should render object as JSON ignore $$', inject(function($rootScope, $compile) { element = $compile('
{{ {key:"value", $$key:"hide"}  }}
')($rootScope); $rootScope.$digest(); @@ -132,18 +79,6 @@ describe('ngBind*', function() { $rootScope.$digest(); expect(angular.lowercase(element.html())).toEqual('
hello
'); })); - - it('should one-time bind if the expression starts with two colons', inject(function($rootScope, $compile) { - element = $compile('
')($rootScope); - $rootScope.html = '
hello
'; - expect($rootScope.$$watchers.length).toEqual(1); - $rootScope.$digest(); - expect(element.text()).toEqual('hello'); - expect($rootScope.$$watchers.length).toEqual(0); - $rootScope.html = '
hello
'; - $rootScope.$digest(); - expect(element.text()).toEqual('hello'); - })); }); diff --git a/test/ng/directive/ngRepeatSpec.js b/test/ng/directive/ngRepeatSpec.js index 90499ef12eb6..8b6ec970d03f 100644 --- a/test/ng/directive/ngRepeatSpec.js +++ b/test/ng/directive/ngRepeatSpec.js @@ -58,42 +58,6 @@ describe('ngRepeat', function() { expect(element.text()).toEqual('shyam;'); }); - it('should be possible to use one-time bindings on the collection', function() { - element = $compile( - '
    ' + - '
  • {{item.name}};
  • ' + - '
')(scope); - - scope.$digest(); - - scope.items = [{name: 'misko'}, {name:'shyam'}]; - scope.$digest(); - expect(element.find('li').length).toEqual(2); - expect(element.text()).toEqual('misko;shyam;'); - scope.items.push({name: 'adam'}); - scope.$digest(); - expect(element.find('li').length).toEqual(2); - expect(element.text()).toEqual('misko;shyam;'); - }); - - it('should be possible to use one-time bindings on the content', function() { - element = $compile( - '
    ' + - '
  • {{::item.name}};
  • ' + - '
')(scope); - - scope.$digest(); - - scope.items = [{name: 'misko'}, {name:'shyam'}]; - scope.$digest(); - expect(element.find('li').length).toEqual(2); - expect(element.text()).toEqual('misko;shyam;'); - scope.items.push({name: 'adam'}); - scope.$digest(); - expect(element.find('li').length).toEqual(3); - expect(element.text()).toEqual('misko;shyam;adam;'); - }); - it('should iterate over an array-like object', function() { element = $compile( diff --git a/test/ng/parseSpec.js b/test/ng/parseSpec.js index ec8aed4faa41..bd02af8da512 100644 --- a/test/ng/parseSpec.js +++ b/test/ng/parseSpec.js @@ -780,7 +780,6 @@ describe('parser', function() { 'disallowed! Expression: wrap["d"]'); })); - it('should NOT allow access to the Window or DOM returned from a function', inject(function($window, $document) { scope.getWin = valueFn($window); scope.getDoc = valueFn($document); @@ -1079,80 +1078,6 @@ describe('parser', function() { })); }); - - describe('one-time binding', function() { - it('should only use the cache when it is not a one-time binding', inject(function($parse) { - expect($parse('foo')).toBe($parse('foo')); - expect($parse('::foo')).not.toBe($parse('::foo')); - })); - - it('should stay stable once the value defined', inject(function($parse, $rootScope) { - var fn = $parse('::foo'); - expect(fn.$$unwatch).not.toBe(true); - $rootScope.$watch(fn); - - $rootScope.$digest(); - expect(fn.$$unwatch).not.toBe(true); - - $rootScope.foo = 'bar'; - $rootScope.$digest(); - expect(fn.$$unwatch).toBe(true); - expect(fn($rootScope)).toBe('bar'); - expect(fn()).toBe('bar'); - - $rootScope.foo = 'man'; - $rootScope.$digest(); - expect(fn.$$unwatch).toBe(true); - expect(fn($rootScope)).toBe('bar'); - expect(fn()).toBe('bar'); - })); - - it('should have a stable value if at the end of a $digest it has a defined value', inject(function($parse, $rootScope) { - var fn = $parse('::foo'); - $rootScope.$watch(fn); - $rootScope.$watch('foo', function() { if ($rootScope.foo === 'bar') {$rootScope.foo = undefined; } }); - - $rootScope.foo = 'bar'; - $rootScope.$digest(); - expect(fn.$$unwatch).toBe(false); - - $rootScope.foo = 'man'; - $rootScope.$digest(); - expect(fn.$$unwatch).toBe(true); - expect(fn($rootScope)).toBe('man'); - expect(fn()).toBe('man'); - - $rootScope.foo = 'shell'; - $rootScope.$digest(); - expect(fn.$$unwatch).toBe(true); - expect(fn($rootScope)).toBe('man'); - expect(fn()).toBe('man'); - })); - - it('should keep a copy of the stable element', inject(function($parse, $rootScope) { - var fn = $parse('::foo'), - value = {bar: 'bar'}; - $rootScope.$watch(fn); - $rootScope.foo = value; - $rootScope.$digest(); - - value.baz = 'baz'; - expect(fn()).toEqual({bar: 'bar'}); - })); - - it('should not throw if the stable value is `null`', inject(function($parse, $rootScope) { - var fn = $parse('::foo'); - $rootScope.$watch(fn); - $rootScope.foo = null; - $rootScope.$digest(); - $rootScope.foo = 'foo'; - $rootScope.$digest(); - expect(fn()).toEqual(null); - })); - - }); - - describe('locals', function() { it('should expose local variables', inject(function($parse) { expect($parse('a')({a: 0}, {a: 1})).toEqual(1); diff --git a/test/ng/rootScopeSpec.js b/test/ng/rootScopeSpec.js index adafaed5d8ae..fa98a86aa325 100644 --- a/test/ng/rootScopeSpec.js +++ b/test/ng/rootScopeSpec.js @@ -114,55 +114,6 @@ describe('Scope', function() { expect($rootScope.$$watchers.length).toEqual(0); })); - it('should not keep constant literals on the watch queue', inject(function($rootScope) { - $rootScope.$watch('[]', function() {}); - $rootScope.$watch('{}', function() {}); - expect($rootScope.$$watchers.length).toEqual(2); - $rootScope.$digest(); - - expect($rootScope.$$watchers.length).toEqual(0); - })); - - it('should clean up stable watches on the watch queue', inject(function($rootScope, $parse) { - $rootScope.$watch($parse('::foo'), function() {}); - expect($rootScope.$$watchers.length).toEqual(1); - - $rootScope.$digest(); - expect($rootScope.$$watchers.length).toEqual(1); - - $rootScope.foo = 'foo'; - $rootScope.$digest(); - expect($rootScope.$$watchers.length).toEqual(0); - })); - - it('should claen up stable watches from $watchCollection', inject(function($rootScope, $parse) { - $rootScope.$watchCollection('::foo', function() {}); - expect($rootScope.$$watchers.length).toEqual(1); - - $rootScope.$digest(); - expect($rootScope.$$watchers.length).toEqual(1); - - $rootScope.foo = []; - $rootScope.$digest(); - expect($rootScope.$$watchers.length).toEqual(0); - })); - - it('should clean up stable watches from $watchGroup', inject(function($rootScope, $parse) { - $rootScope.$watchGroup(['::foo', '::bar'], function() {}); - expect($rootScope.$$watchers.length).toEqual(3); - - $rootScope.$digest(); - expect($rootScope.$$watchers.length).toEqual(3); - - $rootScope.foo = 'foo'; - $rootScope.$digest(); - expect($rootScope.$$watchers.length).toEqual(2); - - $rootScope.bar = 'bar'; - $rootScope.$digest(); - expect($rootScope.$$watchers.length).toEqual(0); - })); - it('should delegate exceptions', function() { module(function($exceptionHandlerProvider) { $exceptionHandlerProvider.mode('log'); diff --git a/test/ng/sceSpecs.js b/test/ng/sceSpecs.js index d3f00d9a010b..dfb260f24742 100644 --- a/test/ng/sceSpecs.js +++ b/test/ng/sceSpecs.js @@ -209,15 +209,6 @@ describe('SCE', function() { expect($sce.parseAsJs('"string"')()).toBe("string"); })); - it('should be possible to do one-time binding', inject(function($sce, $rootScope) { - var exprFn = $sce.parseAsHtml('::foo'); - expect(exprFn($rootScope, {'foo': $sce.trustAs($sce.HTML, 'trustedValue')})).toBe('trustedValue'); - expect(exprFn($rootScope, {'foo': $sce.trustAs($sce.HTML, 'anotherTrustedValue')})).toBe('anotherTrustedValue'); - $rootScope.$digest(); - expect(exprFn($rootScope, {'foo': $sce.trustAs($sce.HTML, 'somethingElse')})).toBe('anotherTrustedValue'); - expect(exprFn.$$unwatch).toBe(true); - })); - it('should NOT parse constant non-literals', inject(function($sce) { // Until there's a real world use case for this, we're disallowing // constant non-literals. See $SceParseProvider.