AngularJS the $scope tree


Example

The previous example is good enough when we need to bind a single html element, to a single variable.

In reality - we need to bind many elements to many variables:

<span ng-repeat="number in [1,2,3,4,5]">{{number}}</span>

This ng-repeat binds 5 elements to 5 variables called number, with a different value for each of them!


The way angular achieves this behavior is using a separate context for each element which needs separate variables. This context is called a scope.

Each scope contains properties, which are the variables bound to the DOM, and the $digest and $watch functions are implemented as methods of the scope.

The DOM is a tree, and variables need to be used in different levels of the tree:

<div>
    <input ng-model="person.name" />
    <span ng-repeat="number in [1,2,3,4,5]">{{number}} {{person.name}}</span>
</div>

But as we saw, the context(or scope) of variables inside ng-repeat is different to the context above it. To solve this - angular implements scopes as a tree.

Each scope has an array of children, and calling its $digest method will run all of its children's $digest method.

This way - after changing the input - $digest is called for the div's scope, which then runs the $digest for its 5 children - which will update its content.


A simple implementation for a scope, could look like this:

function $scope(){
    this.$children = [];
    this.$watches = [];
}

$scope.prototype.$digest = function(){
    this.$watches.forEach(function($w){
        var val = $w.val();
        if($w.prevVal !== val){
            $w.callback(val, $w.prevVal);
          $w.prevVal = val;
        }
    });
    this.$children.forEach(function(c){
        c.$digest();
    });
}

$scope.prototype.$watch = function(val, callback){
    this.$watches.push({val:val, callback:callback, prevVal: val() })
}

note: this is example is a demonstration, not the actual angular code