diff options
Diffstat (limited to 'docs/content/guide/scope.ngdoc')
| -rw-r--r-- | docs/content/guide/scope.ngdoc | 127 |
1 files changed, 98 insertions, 29 deletions
diff --git a/docs/content/guide/scope.ngdoc b/docs/content/guide/scope.ngdoc index 629d3782..342877d7 100644 --- a/docs/content/guide/scope.ngdoc +++ b/docs/content/guide/scope.ngdoc @@ -110,46 +110,46 @@ new child scopes (refer to directive documentation to see which directives creat When new scopes are created, they are added as children of their parent scope. This creates a tree structure which parallels the DOM where they're attached -When Angular evaluates `{{username}}`, it first looks at the scope associated with the given -element for the `username` property. If no such property is found, it searches the parent scope +When Angular evaluates `{{name}}`, it first looks at the scope associated with the given +element for the `name` property. If no such property is found, it searches the parent scope and so on until the root scope is reached. In JavaScript this behavior is known as prototypical inheritance, and child scopes prototypically inherit from their parents. -This example illustrates scopes in application, and prototypical inheritance of properties. +This example illustrates scopes in application, and prototypical inheritance of properties. The example is followed by +a diagram depicting the scope boundaries. +<div class="show-scope"> <example> - <file name="style.css"> - /* remove .doc-example-live in jsfiddle */ - .doc-example-live .ng-scope { - border: 1px dashed red; - } + <file name="index.html"> + <div ng-controller="GreetCtrl"> + Hello {{name}}! + </div> + <div ng-controller="ListCtrl"> + <ol> + <li ng-repeat="name in names">{{name}}</li> + </ol> + </div> </file> <file name="script.js"> - function EmployeeController($scope) { - $scope.department = 'Engineering'; - $scope.employee = { - name: 'Joe the Manager', - reports: [ - {name: 'John Smith'}, - {name: 'Mary Run'} - ] - }; + function GreetCtrl($scope) { + $scope.name = 'World'; + } + + function ListCtrl($scope) { + $scope.names = ['Igor', 'Misko', 'Vojta']; } </file> - <file name="index.html"> - <div ng-controller="EmployeeController"> - Manager: {{employee.name}} [ {{department}} ]<br> - Reports: - <ul> - <li ng-repeat="employee in employee.reports"> - {{employee.name}} [ {{department}} ] - </li> - </ul> - <hr> - {{greeting}} - </div> + <file name="style.css"> + .show-scope .doc-example-live.ng-scope, + .show-scope .doc-example-live .ng-scope { + border: 1px solid red; + margin: 3px; + } </file> </example> +</div> + +<img class="center" src="img/guide/concepts-scope.png"> Notice that Angular automatically places `ng-scope` class on elements where scopes are attached. The `<style>` definition in this example highlights in red the new scope locations. The @@ -329,3 +329,72 @@ the dirty checking function must be efficient. Care should be taken that the dir function does not do any DOM access, as DOM access is orders of magnitude slower then property access on JavaScript object. +## Integration with the browser event loop +<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-runtime.png"> + +The diagram and the example below describe how Angular interacts with the browser's event loop. + + 1. The browser's event-loop waits for an event to arrive. An event is a user interaction, timer event, + or network event (response from a server). + 2. The event's callback gets executed. This enters the JavaScript context. The callback can + modify the DOM structure. + 3. Once the callback executes, the browser leaves the JavaScript context and + re-renders the view based on DOM changes. + +Angular modifies the normal JavaScript flow by providing its own event processing loop. This +splits the JavaScript into classical and Angular execution context. Only operations which are +applied in Angular execution context will benefit from Angular data-binding, exception handling, +property watching, etc... You can also use $apply() to enter Angular execution context from JavaScript. Keep in +mind that in most places (controllers, services) $apply has already been called for you by the +directive which is handling the event. An explicit call to $apply is needed only when +implementing custom event callbacks, or when working with third-party library callbacks. + + 1. Enter Angular execution context by calling {@link guide/scope scope}`.`{@link + api/ng.$rootScope.Scope#methods_$apply $apply}`(stimulusFn)`. Where `stimulusFn` is + the work you wish to do in Angular execution context. + 2. Angular executes the `stimulusFn()`, which typically modifies application state. + 3. Angular enters the {@link api/ng.$rootScope.Scope#methods_$digest $digest} loop. The + loop is made up of two smaller loops which process {@link + api/ng.$rootScope.Scope#methods_$evalAsync $evalAsync} queue and the {@link + api/ng.$rootScope.Scope#methods_$watch $watch} list. The {@link + api/ng.$rootScope.Scope#methods_$digest $digest} loop keeps iterating until the model + stabilizes, which means that the {@link api/ng.$rootScope.Scope#methods_$evalAsync + $evalAsync} queue is empty and the {@link api/ng.$rootScope.Scope#methods_$watch + $watch} list does not detect any changes. + 4. The {@link api/ng.$rootScope.Scope#methods_$evalAsync $evalAsync} queue is used to + schedule work which needs to occur outside of current stack frame, but before the browser's + view render. This is usually done with `setTimeout(0)`, but the `setTimeout(0)` approach + suffers from slowness and may cause view flickering since the browser renders the view after + each event. + 5. The {@link api/ng.$rootScope.Scope#methods_$watch $watch} list is a set of expressions + which may have changed since last iteration. If a change is detected then the `$watch` + function is called which typically updates the DOM with the new value. + 6. Once the Angular {@link api/ng.$rootScope.Scope#methods_$digest $digest} loop finishes + the execution leaves the Angular and JavaScript context. This is followed by the browser + re-rendering the DOM to reflect any changes. + + +Here is the explanation of how the `Hello world` example achieves the data-binding effect when the +user enters text into the text field. + + 1. During the compilation phase: + 1. the {@link api/ng.directive:ngModel ng-model} and {@link + api/ng.directive:input input} {@link guide/directive + directive} set up a `keydown` listener on the `<input>` control. + 2. the {@link api/ng.$interpolate {{name}} } interpolation + sets up a {@link api/ng.$rootScope.Scope#methods_$watch $watch} to be notified of + `name` changes. + 2. During the runtime phase: + 1. Pressing an '`X`' key causes the browser to emit a `keydown` event on the input control. + 2. The {@link api/ng.directive:input input} directive + captures the change to the input's value and calls {@link + api/ng.$rootScope.Scope#methods_$apply $apply}`("name = 'X';")` to update the + application model inside the Angular execution context. + 3. Angular applies the `name = 'X';` to the model. + 4. The {@link api/ng.$rootScope.Scope#methods_$digest $digest} loop begins + 5. The {@link api/ng.$rootScope.Scope#methods_$watch $watch} list detects a change + on the `name` property and notifies the {@link api/ng.$interpolate + {{name}} } interpolation, which in turn updates the DOM. + 6. Angular exits the execution context, which in turn exits the `keydown` event and with it + the JavaScript execution context. + 7. The browser re-renders the view with update text. |
