1. What is Scope?
scope (http://code.angularjs.org/1.0.2/docs/api/ng.$rootScope.Scope) is an object pointing to the application model. It is also the execution context of expression (http://www.cnblogs.com/lclao/archive/2012/09/16/2687162.html). scope is placed in a hierarchy of DOM structures similar to that of application. scope can monitor (watch, $watch) expression and propagation events.
2. The characteristics of scope
3. Scope as Data-Model (scope as data model)
scope is the link between the application controller and the view. In the stage of template linking (http://www.cnblogs.com/lclao/archive/2012/09/04/2669802.html), directive (http://www.cnblogs.com/lclao/archive/2012/09/09/2677190.html) set the $watch expression in scope. $watch allows directive to know the changes in attributes, so directive renders the updated value into the DOM.
Both controllers and directives have reference to the scope, but not to each other. This arrangement separates the controller from the directive and DOM. This is an important place because it isolates the controller from the view, greatly improving the testing story of the applications.
<!DOCTYPE HTML><html lang="zh-cn" ng-app><head> <meta charset="UTF-8"> <title>data-model</title> <style type="text/css"> .ng-cloak { display: none; } </style></head><body><div ng-controller="MyController"> Your name: <input type="text" ng-model="username"/> <button ng-click="sayHello()">Welcome</button> <hr/> {{greeting}}</div><script src="../angular-1.0.1.js" type="text/javascript"></script><script type="text/javascript"> function MyController($scope) { $scope.username = "My Little Dada"; $scope.sayHello = function() { $scope.greeting = "Hello~" + $scope.username + "!"; }; }</script></body></html>In the above example we can notice that MyController assigns the username attribute in scope with "My Little Dada". Then, scope notifies the input for assignment and pre-filling the username value into the input. This shows how the controller can write data into the scope.
Similarly, the controller can attach the behavior to the scope, just like the sayHello method that is triggered when the user clicks the "Welcome" button. The sayHello method can read the username attribute or create a greeting attribute. This shows that when they are bound to an HTML input control, properties in scope are automatically updated.
Logically, displaying {{greeting}} involves the following two points:
Search scope with the template DOM node that defines the {{greeting}} expression. In this example, this scope is the same as the scope passed into the MyController. (We will discuss the scope hierarchy later)
The greeting expression is evaluated through the scope retrieved previously, and the result is then used as the value of the text that encloses the DOM element.
We can think that scope and its own properties can be used as data for rendering views. The scope is the single source-of-truth for all things view related.
From the testability perspective, the separation of controller and view is delighted, as it allows us to (focus on) testing behavior without the interference of rendering details.
it('should say hello', function() { var scopeMock = {}; var cntl = new MyController(scopeMock); // Assert that username is pre-filled expect(scopeMock.username).toEqual('World'); // Assert that we read new username and greet scopeMock.username = 'angular'; scopeMock.sayHello(); expect(scopeMock.greeting).toEqual('Hello angular!');});4. Scope Hierarchies (scope hierarchies)
Each angular application has and only one root scope, but can have multiple child scopes.
An application can have multiple child scopes, because some directives will create new child scopes (see the directive documentation to see which directives can create new scopes, such as ng-repeat). When the new scope is created, they will be added to the parent scope as a child scope. In this way, a tree structure similar to the DOM they are attached is created.
When angular evaluates {{username}}, it first looks at the username property of the scope associated with the current element. If no corresponding property is found, it will search upwards for parent scope until it reaches the root scope. In javascript, this behavior is called "prototype inheritance", and the child scope is typically inherited from their parent.
This example shows the scope (what is it) and the prototype inheritance of properties in the application.
<!DOCTYPE HTML><html lang="zh-cn" ng-app><head> <meta charset="UTF-8"> <title>scope-hierarchies</title> <style type="text/css"> .ng-cloak { display: none; } .ng-scope { border: 1px dashed red; } </style></head><body><div ng-controller="MyController"> Manager: {{employee.name}} [{{department}}] <br/> Report: <ul> <li ng-repeat="employee in employee.reports"> {{employee.name}} [{{department}}] </li> </ul> <hr/> {{greeting}}</div><script src="../angular-1.0.1.js" type="text/javascript"></script><script type="text/javascript"> function MyController($scope) { $scope.department = "a certain unit"; $scope.employee = { name:"My Little Dada", reports: [ {name:"Lclao"}, {name:"Who^o^"} ] }; }</script></body></html>Note that angular automatically places ng-scope class into elements that adhere to scope. <style> is defined in the example above, highlighting the range of the new scope through the red dotted line. Because repeater evaluates the {{employee.name}} expression, child scope is necessary, but depending on which scope the expression is evaluated, different scopes have different results. Similarly, the value of {{department}} is inherited from the prototype in the root scope. Only when there is it, can the department attribute be defined.
5. Retrieving Scopes from the DOM (retrieve scope from the DOM)
scope is attached to the DOM as the $scope data attribute and can be used for retrieval for debugging purposes. (It is impossible to retrieve Scope in this way in the application.) The location of the root scope attached to the DOM is defined by the location of the ng-app directive. Usually ng-app is placed in the <html> element, but it can also be placed in other elements, for example, only a portion of the view needs to be controlled by angular.
View scope in debugger:
1. In the browser, right-click the element you are interested in and select "View Element". We can see that the browser debugger highlights the elements we selected.
2. debugger allows us to access the currently selected element through the $0 variable in the console.
3. If you want to view the associated scope, we can enter: angular.element($0).scope() in the console
6. Scope Events Propagation (Scope Event Propagation)
scope can propagate events in a way similar to DOM events. Events can be broadcast (http://code.angularjs.org/1.0.2/docs/api/ng.$rootScope.Scope#$broadcast) to child scope or emit (http://code.angularjs.org/1.0.2/docs/api/ng.$rootScope.Scope#$emit) to parent scope. (If the current scope is listened, it will also be executed)
<!DOCTYPE HTML><html lang="zh-cn" ng-app><head> <meta charset="UTF-8"> <title>scope-event-propagation</title> <style type="text/css"> .ng-cloak { display: none; } </style></head><body><div ng-controller="MyController"> root scope count:{{count}} <ul> <li ng-repeat="i in [1]" ng-controller="MyController"> <button ng-click="$emit('MyEvent')">$emit("MyEvent")</button> <button ng-click="$broadcast('MyEvent')">$broadcast("MyEvent")</button> <br/> middle scope count:{{count}} <ul> <li ng-repeat="item in [1,2]" ng-controller="MyController"> Leaf scope count:{{count}} </li> </ul> </li> </ul></div><script src="../angular-1.0.1.js" type="text/javascript"></script><script type="text/javascript"> function MyController($scope) { $scope.count = 0; $scope.$on("MyEvent", function() { $scope.count++; }); }</script></body></html>7. Scope Life Cycle (scope life cycle)
In the normal event stream of the browser, when the browser receives the event, it will execute a corresponding javascript callback. Once the callback function is executed, the browser will redraw the DOM and return to the state where you continue to wait for the event.
When the browser calls javascript code outside the angular execution environment, this means that angular does not know the change of the model. To correctly handle the modification of the model, this command must enter the angular execution environment by making the $apply method. Only when the model changes in the $apply method will be correctly counted by angular. For example, a directive listens for a DOM event, such as ng-click, which must evaluate the expression in the $apply method.
After evaluating the expression, the $apply method executes a $digest. In the $digest stage, scope checks all the expressions listened to by $watch, and compares the current value with the old value. Dirty checking is asynchronous. This means that the assignment statement (for example, $scope.username="angular") will not immediately cause a $watch to be notified, but the notification of $watch will be delayed to the $digest stage. This delay is necessary because it combines multiple model updates into a $watch notification, which ensures that no other $watch is being executed during the $watch notification process. If a $watch changes the value of the model, it will force an increase of a $digest cycle.
1) Creation (create scope)
The root scope is created by $injector (http://code.angularjs.org/1.0.2/docs/api/AUTO.$injector) during the application startup process. During the template linking process, some directives will create a new child scope.
2) Watcher registration (register watcher)
During the template linking process, directive registers $watch in scope. These watches will be used as the value of propagating the model to the DOM.
3) Model mutation (Model changes)
In order for changes to be detected correctly, we need to wrap them in scope.$apply. (The angular API has done this implicitly, so when doing synchronous work in the controller or asynchronous work with $http or $timeout, no additional $apply call is required).
4) Mutation observation (change monitoring)
At the end of $apply, angular will execute a $digest cycle in the root scope, which will propagate to all child scopes. In the $digest cycle, all expressions or functions registered with $watch will be checked to determine whether the model has changed. If the change occurs, the corresponding $watch listener will be called.
5) Scope destruction (scope destruction)
When child scope is no longer necessary, it is the responsibility of the child scope producer to destroy them through the scope.$destroy() API. This will stop the $digest call propagation into the child scope, so that the memory used by the child scope model can be recycled by gc (garbage collector).
1. Scopes and Directives
During the compilation phase, compiler relies on DOM template matching directive. Directives can usually be divided into two categories:
Observing directives, such as dobule-curly expression {{expression}}, register the listener using the $watch method. Whenever the expression (value) changes, such directives must be notified to update the view.
Listener directive, such as ng-click, registers a listener into the DOM. When the DOM's listener fires, directive executes the relevant expression and updates the view by using the $apply method.
When an external event (such as user action, timer, or XHR) is heard, the relevant expression must be applied to the scope through the $apply method, so that all listeners can be updated correctly.
2. Directives that Create Scopes
In most cases, directive and scope are mutually influencing, but no new scope instance is created. However, some directives (such as ng-controller and ng-repeat) create a new scope, appending a child scope to the corresponding DOM element. We view the scope of any DOM element by using angular.element(aDomElement).scope().
3. Controllers and Scopes
In the following cases, scope and controller influence each other:
4. Scope $watch Performance Considerations (Scope $watch performance considerations)
In angular, it is a common operation to perform dirty checking on scope to detect changes in attributes. To do this, this requires that the dirty checking function must be efficient. Be careful that dirty checking functions do not do any DOM access operations, because DOM access is orders of magnitude slower than accessing javascript object properties.
The above is the information about AngularJS Scope. We will continue to add relevant information in the future. Thank you for your support for this site!