diff options
| author | Misko Hevery | 2011-08-11 15:19:26 -0700 |
|---|---|---|
| committer | Misko Hevery | 2011-08-12 16:18:41 -0700 |
| commit | 3f99cdbdc30e85c2100acd7cbe67052befd08776 (patch) | |
| tree | dd16babb99b2874cdde91cecde85e1d1ed6e7ccd | |
| parent | 13e7df68a65b0dd2eb4eed673f7b8e3e702d72a9 (diff) | |
| download | angular.js-3f99cdbdc30e85c2100acd7cbe67052befd08776.tar.bz2 | |
feat(scope): $evalAsync support
| -rw-r--r-- | CHANGELOG.md | 4 | ||||
| -rw-r--r-- | src/Scope.js | 38 | ||||
| -rw-r--r-- | test/ScopeSpec.js | 35 |
3 files changed, 77 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index d2c3704e..f60c9b17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ <a name="0.9.19"><a/> # 0.9.19 canine-psychokinesis (in-progress) # +### Features +- Scope $evalAsync() + + # Breaking Changes - Controller constructor functions are now looked up on scope first and then on window. - angular.equals now use === which means that things which used to be equal are no longer. diff --git a/src/Scope.js b/src/Scope.js index ffac1317..af956de2 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -96,6 +96,7 @@ function Scope() { this.$$phase = this.$parent = this.$$watchers = this.$$nextSibling = this.$$childHead = this.$$childTail = null; this['this'] = this.$root = this; + this.$$asyncQueue = []; } /** @@ -168,6 +169,7 @@ Scope.prototype = { child['this'] = child; child.$parent = this; child.$id = nextUid(); + child.$$asyncQueue = []; child.$$phase = child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null; if (this.$$childHead) { @@ -319,6 +321,7 @@ Scope.prototype = { var child, watch, value, last, watchers = this.$$watchers, + asyncQueue = this.$$asyncQueue, length, count = 0, dirtyCount, ttl = 100, recheck = !this.$parent || !this.$parent.$$phase; @@ -328,6 +331,13 @@ Scope.prototype = { } this.$$phase = '$digest'; do { + while(asyncQueue.length) { + try { + this.$eval(asyncQueue.shift()); + } catch (e) { + this.$service('$exceptionHandler')(e); + } + } dirtyCount = 0; if (watchers) { // process our watches @@ -441,6 +451,34 @@ Scope.prototype = { /** * @workInProgress * @ngdoc function + * @name angular.scope.$evalAsync + * @function + * + * @description + * Executes the expression on the current scope at a later point in time. + * + * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only that: + * + * - it will execute in the current script execution context (before any DOM rendering). + * - at least one {@link angular.scope.$digest $digest cycle} will be performed after + * `expression` execution. + * + * Any exceptions from the execution of the expression are forwarded to the + * {@link angular.service.$exceptionHandler $exceptionHandler} service. + * + * @param {(string|function())=} expression An angular expression to be executed. + * + * - `string`: execute using the rules as defined in {@link guide/dev_guide.expressions expression}. + * - `function(scope)`: execute the function with the current `scope` parameter. + * + */ + $evalAsync: function(expr) { + this.$$asyncQueue.push(expr); + }, + + /** + * @workInProgress + * @ngdoc function * @name angular.scope.$apply * @function * diff --git a/test/ScopeSpec.js b/test/ScopeSpec.js index 5a14abd6..b3edad6c 100644 --- a/test/ScopeSpec.js +++ b/test/ScopeSpec.js @@ -306,6 +306,41 @@ describe('Scope', function(){ }); }); + describe('$evalAsync', function(){ + + it('should run callback before $watch', function(){ + var log = ''; + var child = root.$new(); + root.$evalAsync(function(scope){ log += 'parent.async;'; }); + root.$watch('value', function(){ log += 'parent.$digest;'; }); + child.$evalAsync(function(scope){ log += 'child.async;'; }); + child.$watch('value', function(){ log += 'child.$digest;'; }); + root.$digest(); + expect(log).toEqual('parent.async;parent.$digest;child.async;child.$digest;'); + }); + + it('should cause a $digest rerun', function(){ + root.log = ''; + root.value = 0; + root.$watch('value', 'log = log + ".";'); + root.$watch('init', function(){ + root.$evalAsync('value = 123; log = log + "=" '); + expect(root.value).toEqual(0); + }); + root.$digest(); + expect(root.log).toEqual('.=.'); + }); + + it('should run async in the same order as added', function(){ + root.log = ''; + root.$evalAsync("log = log + 1"); + root.$evalAsync("log = log + 2"); + root.$digest(); + expect(root.log).toBe('12'); + }); + + }); + describe('$apply', function(){ it('should apply expression with full lifecycle', function(){ |
