What are Scopes?
scope
is an object that refers to the application model. It is an execution context for expressions. Scopes are arranged in hierarchical structure which mimic the DOM structure of the application. Scopes can watch expressions and propagate events.
Scope characteristics
Scopes provide APIs (
$watch
) to observe model mutations.Scopes provide APIs (
$apply
) to propagate any model changes through the system into the view from outside of the "Angular realm" (controllers, services, Angular event handlers).Scopes can be nested to isolate application components while providing access to shared model properties. A scope (prototypically) inherits properties from its parent scope.
Scopes provide context against which expressions are evaluated. For example
{{username}}
expression is meaningless, unless it is evaluated against a specific scope which defines theusername
property.
Scope as Data-Model
Scope is the glue between application controller and the view. During the template linking phase the directives
set up $watch
expressions on the scope. The $watch
allows the directives to be notified of property changes, which allows the directive to render the updated value to the DOM.
Both controllers and directives have reference to the scope, but not to each other. This arrangement isolates the controller from the directive as well as from DOM. This is an important point since it makes the controllers view agnostic, which greatly improves the testing story of the applications.
Source
- <!doctype html>
- <htmlng-app>
- <head>
- <scriptsrc="http://code.angularjs.org/angular-1.0.2.min.js"></script>
- <scriptsrc="script.js"></script>
- </head>
- <body>
- <divng-controller="MyController">
- Your name:
- <inputtype="text"ng-model="username">
- <buttonng-click='sayHello()'>greet</button>
- <hr>
- {{greeting}}
- </div>
- </body>
- </html>
Demo
Hello World!
In the above example notice that the MyController
assigns World
to the username
property of the scope. The scope then notifies the input
of the assignment, which then renders the input with username pre-filled. This demonstrates how a controller can write data into the scope.
Similarly the controller can assign behavior to scope as seen by the sayHello
method, which is invoked when the user clicks on the 'greet' button. The sayHello
method can read the username
property and create a greeting
property. This demonstrates that the properties on scope update automatically when they are bound to HTML input widgets.
Logically the rendering of {{greeting}}
involves:
retrieval of the scope associated with DOM node where
{{greeting}}
is defined in template. In this example this is the same scope as the scope which was passed intoMyController
. (We will discuss scope hierarchies later.)Evaluate the
greeting
expression against the scope retrieved above, and assign the result to the text of the enclosing DOM element.
You can think of the scope and its properties as the data which is used to render the view. The scope is the single source-of-truth for all things view related.
From testability, the separation of the controller and the view is desirable, because it allows us to test the behavior without being distracted by the rendering details.
- it('should say hello',function(){
- var scopeMock ={};
- var cntl =newMyController(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!');
- });
Scope Hierarchies
Each Angular application has exactly one root scope
, but may have several child scopes.
The application can have multiple scopes, because some directives create new child scopes (refer to directive documentation to see which directives create new scopes). 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 theusername
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.
Source
- <!doctype html>
- <htmlng-app>
- <head>
- <scriptsrc="http://code.angularjs.org/angular-1.0.2.min.js"></script>
- <scriptsrc="script.js"></script>
- </head>
- <body>
- <divng-controller="EmployeeController">
- Manager: {{employee.name}} [ {{department}} ]<br>
- Reports:
- <ul>
- <ling-repeat="employee in employee.reports">
- {{employee.name}} [ {{department}} ]
- </li>
- </ul>
- <hr>
- {{greeting}}
- </div>
- </body>
- </html>
Demo
Reports:
- John Smith [ Engineering ]
- Mary Run [ Engineering ]
Notice that the 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 child scopes are necessary because the repeater evaluates {{employee.name}}
expression, but depending on which scope the expression is evaluated it produces different result. Similarly the evaluation of {{department}}
prototypically inherits from root scope, as it is the only place where the department
property is defined.
Retrieving Scopes from the DOM.
Scopes are attached to the DOM as $scope
data property, and can be retrieved for debugging purposes. (It is unlikely that one would need to retrieve scopes in this way inside the application.) The location where the root scope is attached to the DOM is defined by the location of ng-app
directive. Typically ng-app
is placed an the <html>
element, but it can be placed on other elements as well, if, for example, only a portion of the view needs to be controlled by angular.
To examine the scope in the debugger:
right click on the element of interest in your browser and select 'inspect element'. You should see the browser debugger with the element you clicked on highlighted.
The debugger allows you to access the currently selected element in the console as
$0
variable.To retrieve the associated scope in console execute:
angular.element($0).scope()
Scope Events Propagation
Scopes can propagate events in similar fashion to DOM events. The event can be broadcasted
to the scope children or emitted
to scope parents.
Source
- <!doctype html>
- <htmlng-app>
- <head>
- <scriptsrc="http://code.angularjs.org/angular-1.0.2.min.js"></script>
- <scriptsrc="script.js"></script>
- </head>
- <body>
- <divng-controller="EventController">
- Root scope <tt>MyEvent</tt> count: {{count}}
- <ul>
- <ling-repeat="i in [1]"ng-controller="EventController">
- <buttonng-click="$emit('MyEvent')">$emit('MyEvent')</button>
- <buttonng-click="$broadcast('MyEvent')">$broadcast('MyEvent')</button>
- <br>
- Middle scope <tt>MyEvent</tt> count: {{count}}
- <ul>
- <ling-repeat="item in [1, 2]"ng-controller="EventController">
- Leaf scope <tt>MyEvent</tt> count: {{count}}
- </li>
- </ul>
- </li>
- </ul>
- </div>
- </body>
- </html>
Demo
- $emit('MyEvent') $broadcast('MyEvent')
Middle scope MyEvent count: 0- Leaf scope MyEvent count: 0
- Leaf scope MyEvent count: 0
Scope Life Cycle
The normal flow of browser receiving an event is that it executes a corresponding JavaScript callback. Once the callback completes the browser re-renders the DOM and returns to waiting for more events.
When the browser calls into JavaScript the code executes outside the Angular execution context, which means that Angular is unaware of model modifications. To properly process model modifications the execution has to enter the Angular execution context using the $apply
method. Only model modifications which execute inside the $apply
method will be properly accounted for by Angular. For example if a directive listens on DOM events, such as ng-click
it must evaluate the expression inside the $apply
method.
After evaluating the expression, the $apply
method performs a $digest
. In the $digest phase the scope examines all of the $watch
expressions and compares them with the previous value. This dirty checking is done asynchronously. This means that assignment such as $scope.username="angular"
will not immediately cause a $watch
to be notified, instead the $watch
notification is delayed until the $digest
phase. This delay is desirable, since it coalesces multiple model updates into one $watch
notification as well as it guarantees that during the $watch
notification no other $watch
es are running. If a $watch
changes the value of the model, it will force additional$digest
cycle.
Creation
The
root scope
is created during the application bootstrap by the$injector
. During template linking, some directives create new child scopes.Watcher registration
During template linking directives register
watches
on the scope. These watches will be used to propagate model values to the DOM.Model mutation
For mutations to be properly observed, you should make them only within the
scope.$apply()
. (Angular APIs do this implicitly, so no extra$apply
call is needed when doing synchronous work in controllers, or asynchronous work with$http
or$timeout
services.Mutation observation
At the end
$apply
, Angular performs a$digest
cycle on the root scope, which then propagates throughout all child scopes. During the$digest
cycle, all$watch
ed expressions or functions are checked for model mutation and if a mutation is detected, the$watch
listener is called.Scope destruction
When child scopes are no longer needed, it is the responsibility of the child scope creator to destroy them via
scope.$destroy()
API. This will stop propagation of$digest
calls into the child scope and allow for memory used by the child scope models to be reclaimed by the garbage collector.
Scopes and Directives
During the compilation phase, the compiler matches directives
against the DOM template. The directives usually fall into one of two categories:
Observing
directives
, such as double-curly expressions{{expression}}
, register listeners using the$watch()
method. This type of directive needs to be notified whenever the expression changes so that it can update the view.Listener directives, such as
ng-click
, register a listener with the DOM. When the DOM listener fires, the directive executes the associated expression and updates the view using the$apply()
method.
When an external event (such as a user action, timer or XHR) is received, the associated expression must be applied to the scope through the $apply()
method so that all listeners are updated correctly.
Directives that Create Scopes
In most cases, directives
and scopes interact but do not create new instances of scope. However, some directives, such as ng-controller
and ng-repeat
, create new child scopes and attach the child scope to the corresponding DOM element. You can retrieve a scope for any DOM element by using anangular.element(aDomElement).scope()
method call.
Controllers and Scopes
Scopes and controllers interact with each other in the following situations:
Controllers use scopes to expose controller methods to templates (see
ng-controller
).Controllers define methods (behavior) that can mutate the model (properties on the scope).
Controllers may register
watches
on the model. These watches execute immediately after the controller behavior executes.
See the ng-controller
for more information.
Scope $watch
Performance Considerations
Dirty checking the scope for property changes is a common operation in Angular and for this reason the dirty checking function must be efficient. Care should be taken that the dirty checking function does not do any DOM access, as DOM access is orders of magnitude slower then property access on JavaScript object.
What are Scopes?的更多相关文章
- AnjularJS系列5 —— scopes、module、controller
第五篇, scopes.module.controller 这一篇,感觉,在前面几篇就使用过的属性,但,总觉得没有理解透彻,有待完善!~ 1.scopes A.定义:$scope是一个把view(一个 ...
- Python Scopes and Namespaces
Before introducing classes, I first have to tell you something about Python's scope rules. Class def ...
- 大漠推荐的教程:创建你自己的AngularJS -- 第一部分 Scopes
创建你自己的AngularJS -- 第一部分 Scopes http://www.html-js.com/article/1863
- IdentityServer4之Clients、Scopes、Claims与Token关联
IdentityServer4之Clients.Scopes.Claims与Token关联 参考 官方文档:client.identity_resource.api_resource:三类配置项介绍描 ...
- The confusion about jsp four scopes and ServletContext,HttpSession,HttpServletReqest,PageContext
The jsp four scopes are same with ServletContext,HttpSession,HttpServletRequest,PageContext? How ser ...
- Swinject 源码框架(三):Object Scopes
Object Scopes 指定了生成的实例在系统中是如何被共享的. 如何指定 scope container.register(Animal.self) { _ in Cat() } .inObje ...
- spring作用域(Spring Bean Scopes Example)
http://docs.spring.io/spring/docs/2.0.x/reference/beans.html#beans-factory-scopes In Spring, bean sc ...
- Subnet Pools and Address Scopes
Why is IPAM important for Neutron? •No VM connectivity without a valid IP assigned •Duplicate subne ...
- 【AnjularJS系列5 】— scopes、module、controller
第五篇, scopes.module.controller 这一篇,感觉,在前面几篇就使用过的属性,但,总觉得没有理解透彻,有待完善!~ 1.scopes A.定义:$scope是一个把view(一个 ...
随机推荐
- Java 字符流实现文件读写操作(FileReader-FileWriter)
Java 字符流实现文件读写操作(FileReader-FileWriter) 备注:字符流效率高,但是没有字节流底层 字节流地址:http://pengyan5945.iteye.com/blog/ ...
- C#调用C、C++结构体数组的方法总结
一个客户要使用C#调用我们用C++开发的一个动态链接库,本来我没有C#的开发经验,就随便写了一个例程.以为很简单就可以搞定,没想到客户开发的过程中遇到了不少问题,最困难的就是用C#调用C++接口中的自 ...
- NSTimer定时器类
NSTimer是Cocoa中比较常用的定时器类,基本操作如下: handleTimer方法可以自行定义.在需要的地方创建timer即可,handleTimer就可以每0.5秒执行一次. - (vo ...
- LiteHttp:一款‘智能’的HTTP框架类库
LiteHttp:一款‘智能’的HTTP框架类库(转自github) 简介 LiteHttp是一款简单.智能.灵活的HTTP框架库,它在请求和响应层面做到了全自动构建和解析,主要用于Android快速 ...
- 11g RAC R2 体系结构---用户及用户组
10.2 RAC 到11.2 RAC 用户及用户组的变化: 在10.2 RAC 的部署中,只需要一个用户(oracle)和一个用户组(dba).Database.Clusterware都是用oracl ...
- jquery-easyui中datagrid扩展,隐藏显示表头功能
今天,后台中需要新增一个功能,用户可以自由选择显示的列,之后保存到本地localStroage中.所以扩展了easyui中datagrid的onHeaderContextMenu方法. 使用方法: _ ...
- Linux nmon 监控工具使用
Linux 系统下监控指标及指标查看 一.工具介绍 Linux 系统下资源监控使用nmon 工具.它可以帮助在一个屏幕上显示所有重要的性能优化信息,并动态地对其进行更新且并不会消耗大量的CPU ...
- C++中的struct和class的区别
C++中的struct对C中的struct进行了扩充,它已经不再只是一个包含不同数据类型的数据结构了,它已经获取了太多的功能.struct能包含成员函数吗? 能!struct能继承吗? 能!!stru ...
- .NET中如何使用反序列化JSON字符串/序列化泛型对象toJsonStr
在进行 .NET Web MVC 框架开发的网站程序的时候,我们都会遇到最关键的问题,数据传输. .NET MVC 4中的ControllerBase类建议我们用ViewBag动态数据字典形式(t ...
- Google Code Jam 2015 Round1A 题解
快一年没有做题了, 今天跟了一下 GCJ Round 1A的题目, 感觉难度偏简单了, 很快搞定了第一题, 第二题二分稍微考了一下, 还剩下一个多小时, 没仔细想第三题, 以为 前两个题目差不多可以晋 ...