Scope is a JavaScript object and the execution context for expressions. You can think about scopes as JavaScript objects that have extra APIs for registering watchers. A scope is the model in the model-view-controller design pattern.
A few other characteristics of scopes:
becomes
this
for a controller.$eval
is used to update its view.watch
properties and fire events.Scopes can be created by calling angular.scope()
or by compiling HTML.
Widgets
and data bindings register listeners on the current scope to be
notified of changes to the scope state. When notified, these listeners push the updated state
through to the DOM.
Here is a simple scope snippet to show how you can interact with the scope.
var scope = angular.scope(); scope.salutation = 'Hello'; scope.name = 'World'; expect(scope.greeting).toEqual(undefined); scope.$watch('name', function(){ this.greeting = this.salutation + ' ' + this.name + '!'; }); expect(scope.greeting).toEqual('Hello World!'); scope.name = 'Misko'; // scope.$eval() will propagate the change to listeners expect(scope.greeting).toEqual('Hello World!'); scope.$eval(); expect(scope.greeting).toEqual('Hello Misko!');
A scope can inherit from a parent scope, as in this example:
var parent = angular.scope(); var child = angular.scope(parent); parent.salutation = "Hello"; child.name = "World"; expect(child.salutation).toEqual('Hello'); child.salutation = "Welcome"; expect(child.salutation).toEqual('Welcome'); expect(parent.salutation).toEqual('Hello');
Scope also acts as a simple dependency injection framework.
TODO: more info needed
Anyone can update a scope by calling its $eval()
method. By default
angular widgets listen to user change events (e.g. the user enters text into a text field), copy
the data from the widget to the scope (the MVC model), and then call the $eval()
method on the
root scope to update dependents. This creates a spreadsheet-like behavior: the bound views update
immediately as the user types into the text field.
Similarly, when a request to fetch data from a server is made and the response comes back, the data is written into the model and then $eval() is called to push updates through to the view and any other dependents.
Because a change in the model that's triggered either by user input or by server response calls
$eval()
, it is unnecessary to call $eval()
from within your controller. The only time when
calling $eval()
is needed is when implementing a custom widget or service.
Because scopes are inherited, the child scope $eval()
overrides the parent $eval()
method.
So to update the whole page you need to call $eval()
on the root scope as $root.$eval()
.
Note: A widget that creates scopes (i.e. ng:repeat
) is
responsible for forwarding $eval()
calls from the parent to those child scopes. That way,
calling $eval() on the root scope will update the whole page.
This example demonstrates scope inheritance and property overriding.
In this example, the root scope encompasses the whole HTML DOM tree. This scope has salutation
,
name
, and names
properties. The ng:repeat
creates a child
scope, one for each element in the names array. The repeater also assigns $index and name into
the child scope.
Notice that:
<ul ng:init="salutation='Hello'; name='Misko'; names=['World', 'Earth']"> <li ng:repeat="name in names"> {{$index}}: {{salutation}} {{name}}! </li> </ul> <pre> $index={{$index}} salutation={{salutation}} name={{name}}</pre>
it('should inherit the salutation property and override the name property', function() { expect(using('.doc-example-live').repeater('li').row(0)). toEqual(['0', 'Hello', 'World']); expect(using('.doc-example-live').repeater('li').row(1)). toEqual(['1', 'Hello', 'Earth']); expect(using('.doc-example-live').element('pre').text()). toBe(' $index=\n salutation=Hello\n name=Misko'); });