angular.scope

Work in Progress This page is currently being revised. It might be incomplete or contain inaccuracies.

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:

Basic Operations

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!');

Inheritance

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');

Dependency Injection

Scope also acts as a simple dependency injection framework.

TODO: more info needed

When scopes are evaluated

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.

Example

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');
       });