| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
 | @ngdoc overview
@name Developer Guide: Scopes: Scope Internals
@description
## What is a scope?
A scope is an execution context for {@link dev_guide.expressions expressions}. You can think of a
scope as a JavaScript object that has an extra set of APIs for registering change listeners and for
managing its own life cycle.  In Angular's implementation of the model-view-controller design
pattern, a scope's properties comprise both the model and the controller methods.
### Scope characteristics
- Scopes provide APIs ({@link api/angular.module.ng.$rootScope.Scope#$watch $watch}) to observe model mutations.
- Scopes provide APIs ({@link api/angular.module.ng.$rootScope.Scope#$apply $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.
- In some parts of the system (such as controllers, services and directives), the scope is made
available as `this` within the given context. (Note: This api will change before 1.0 is released.)
### Root scope
Every application has a root scope, which is the ancestor of all other scopes.
### What is scope used for?
{@link dev_guide.expressions Expressions} in the view are {@link api/angular.module.ng.$rootScope.Scope#$eval evaluated}
against the current scope. When HTML DOM elements are attached to a scope, expressions in those
elements are evaluated against the attached scope.
There are two kinds of expressions:
- Binding expressions, which are observations of property changes. Property changes are reflected
in the view during the {@link api/angular.module.ng.$rootScope.Scope#$digest digest cycle}.
- Action expressions, which are expressions with side effects. Typically, the side effects cause
execution of a method in a controller in response to a user action, such as clicking on a button.
### Scope inheritance
A scope (prototypically) inherits properties from its parent scope. Since a given property may not
reside on a child scope, if a property read does not find the property on a scope, the read will
recursively check the parent scope, grandparent scope, etc. all the way to the root scope before
defaulting to undefined.
{@link api/angular.module.ng.$compileProvider.directive directives} associated with elements
(ngController, ngRepeat, ngInclude, etc.) create new child scopes that inherit properties from
the current parent scope. Any code in Angular is free to create a new scope. Whether or not your
code does so is an implementation detail of the directive, that is, you can decide when or if this
happens. Inheritance typically mimics HTML DOM element nesting, but does not do so with the same
granularity.
A property write will always write to the current scope. This means that a write can hide a parent
property within the scope it writes to, as shown in the following example.
<pre>
it('should inherit properties', inject(function($rootScope)) {
  var root = $rootScope;
  var child = root.$new();
  root.name = 'angular';
  expect(child.name).toEqual('angular');
  expect(root.name).toEqual('angular');
  child.name = 'super-heroic framework';
  expect(child.name).toEqual('super-heroic framework');
  expect(root.name).toEqual('angular');
});
</pre>
### Scope life cycle
1. **Creation**
   * The root scope is created by the  {@link api/angular.module.ng.$rootScope $rootScope} service.
   * To create a child scopes, you should call {@link api/angular.module.ng.$rootScope.Scope#$new parentScope.$new()}.
2. **Watcher registration**
   Watcher registration can happen at any time and on any scope (root or child) via {@link
api/angular.module.ng.$rootScope.Scope#$watch scope.$watch()} API.
3. **Model mutation**
   For mutations to be properly observed, you should make them only within the execution of the
function passed into {@link api/angular.module.ng.$rootScope.Scope#$apply scope.$apply()} call. (Angular apis do this
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers, or
asynchronous work with {@link api/angular.module.ng.$http $http} or {@link api/angular.module.ng.$defer
$defer} services.
4. **Mutation observation**
   At the end of each `$apply` call {@link api/angular.module.ng.$rootScope.Scope#$digest $digest} cycle is started on
the root scope, which then propagates throughout all child scopes.
   During the `$digest` cycle, all `$watch-ers` expressions or functions are checked for model
mutation and if a mutation is detected, the `$watch-er` listener is called.
5. **Scope destruction**
   When child scopes are no longer needed, it is the responsibility of the child scope creator to
destroy them via {@link api/angular.module.ng.$rootScope.Scope#$destroy 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.
   The root scope can't be destroyed via the `$destroy` API. Instead, it is enough to remove all
references from your application to the scope object and garbage collector will do its magic.
## Scopes in Angular applications
To understand how Angular applications work, you need to understand how scopes work within an
application. This section describes the typical life cycle of an application so you can see how
scopes come into play throughout and get a sense of their interactions.
### How scopes interact in applications
1. At application compile time, a root scope is created and is attached to the root `<HTML>` DOM
element.
2. During the compilation phase, the {@link dev_guide.compiler compiler} matches {@link
api/angular.module.ng.$compileProvider.directive directives} against the DOM template. The directives
usually fall into one of two categories:
   - Observing {@link api/angular.module.ng.$compileProvider.directive directives}, such as double-curly
    expressions `{{expression}}`, register listeners using the {@link
    api/angular.module.ng.$rootScope.Scope#$watch $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 {@link api/angular.module.ng.$compileProvider.directive.ngClick
   ngClick}, register a listener with the DOM. When the DOM listener fires, the directive executes
   the associated expression and updates the view using  the {@link
   api/angular.module.ng.$rootScope.Scope#$apply $apply()} method.
3. When an external event (such as a user action, timer or XHR) is received, the associated {@link
dev_guide.expressions expression} must be applied to the scope through the {@link
api/angular.module.ng.$rootScope.Scope#$apply $apply()} method so that all listeners are updated correctly.
### Directives that create scopes
In most cases, {@link api/angular.module.ng.$compileProvider.directive directives} and scopes interact but do not create new
instances of scope. However, some directives, such as {@link api/angular.module.ng.$compileProvider.directive.ngController
ngController} and {@link api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat}, create new child scopes using
the {@link api/angular.module.ng.$rootScope.Scope#$new $new()} method and then attach the child scope to the
corresponding DOM element. You can retrieve a scope for any DOM element by using an
`angular.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 {@link
api/angular.module.ng.$compileProvider.directive.ngController ngController}).
   - Controllers define methods (behavior) that can mutate the model (properties on the scope).
   - Controllers may register {@link api/angular.module.ng.$rootScope.Scope#$watch watches} on the model. These watches
execute immediately after the controller behavior executes, but before the DOM gets updated.
See the {@link dev_guide.mvc.understanding_controller controller docs} for more information.
### Updating scope properties
You can update a scope by calling its {@link api/angular.module.ng.$rootScope.Scope#$apply $apply()} method with an
expression or a function as the function argument. However it is typically not necessary to do this
explicitly. In most cases, angular intercepts all external events (such as user interactions, XHRs,
and timers) and wraps their callbacks into the `$apply()` method call on the scope object for you
at the right time. The only time you might need to call `$apply()` explicitly is when you create
your own custom asynchronous widget or service.
The reason it is unnecessary to call `$apply()` from within your controller functions when you use
built-in angular widgets and services is because your controllers are typically called from within
an `$apply()` call already.
When a user inputs data, angularized widgets invoke `$apply()` on the current scope and evaluate an
angular expression or execute a function on this scope. Afterwards `$apply` will trigger `$digest`
call on the root scope, to propagate your changes through the entire system, which results in
$watch-ers firing and view getting updated. Similarly, when a request to fetch data from a server
is made and the response comes back, the data is written into the model (scope) within an $apply,
which then pushes updates through to the view and any other dependents.
A widget that creates scopes (such as {@link api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat}) via `$new`,
doesn't need to worry about propagating the `$digest` call from the parent scope to child scopes.
This happens automatically.
## Scopes in unit-testing
You can create scopes, including the root scope, in tests by having the $rootScope injected into
your spec. This allows you to mimic the run-time environment and have full control over
the life cycle of the scope so that you can assert correct model transitions. Since these scopes
are created outside the normal compilation process, their life cycles must be managed by the test.
### Using scopes in unit-testing
The following example demonstrates how the scope life cycle needs to be manually triggered from
within the unit-tests.
<pre>
  // example of a test
  it('should trigger a watcher', inject(function($rootScope) {
    var scope = $rootScope;
    scope.$watch('name', function(name) {
     scope.greeting = 'Hello ' + name + '!';
    });
    scope.name = 'angular';
    // The watch does not fire yet since we have to manually trigger the digest phase.
    expect(scope.greeting).toEqual(undefined);
    // manually trigger digest phase from the test
    scope.$digest();
    expect(scope.greeting).toEqual('Hello Angular!');
  }
</pre>
### Dependency injection in Tests
When you find it necessary to inject your own mocks in your tests, use a scope to override the
service instances, as shown in the following example.
<pre>
it('should allow override of providers', inject(
  function($provide) {
    $provide.value('$location', {mode:'I am a mock'});
  },
  function($location){
    expect($location.mode).toBe('I am a mock');
  }
)};
</pre>
## Related Topics
* {@link dev_guide.scopes Angular Scope Objects}
* {@link dev_guide.scopes.understanding_scopes Understanding Scopes}
## Related API
* {@link api/angular.module.ng.$rootScope.Scope Angular Scope API}
 |