AngularJS Abstractions: Scope

Thursday, May 16, 2013

Continuing from the controllers post, the parameter to the controller function is named $scope.

var AboutController = function($scope) {

    // ...    

};

The name $scope is important since it allows the AngularJS dependency injector to know what type of object you are asking for, in this case an object that will contain the view model. Any plain old JavaScript you attach to $scope (properties, functions, objects, arrays) is eligible to use from the expressions inside the view.

In the last post our model was relatively “flat” in the sense that properties and functions were added directly to $scope:

$scope.rabbitCount = 2;

$scope.increase = function() {
    $scope.rabbitCount *= $scope.rabbitCount;
};

This allowed us to use rabbitCount and increase() in the markup that was inside the view scope (the div) of the AboutController:

<div data-ng-controller="AboutController">

    <div>Number of rabbits in the yard: {{rabbitCount}}</div>

    <button ng-click="increase()">More rabbits</button>
    
</div>

You can think of $scope as the execution context for the expressions in the view. Saying ng-click=”increase” results in a call to $scope.increase. The only thing tricky to understand about $scope is that having a controller inside a controller, or a controller inside an application (which you’ll always have), will result in nested $scopes, and a nested $scope will prototypally inherit from it’s parent scope by default. This is why $scope is injected by angularJS – the framework sets up the prototype chain before giving your controller the $scope object to use as a model.

Inheritance means a view has access to it’s own scope as well as any inherited scope. In the following example, the view inside the ChildController markup can use an expression like {{rabbitCount}}, and this expression will read the rabbitCount property of AboutController’s scope ($scope.rabbitCount will follow the prototype chain).

<div data-ng-controller="AboutController">    

    <div>Number of rabbits in the yard: {{rabbitCount}}</div>
    
    <div data-ng-controller="ChildController">
        Number of rabbits in the yard: {{rabbitCount}}
        Number of squirrels in the yard: {{squirrelCount}}
    </div>

</div>

The one place to be careful with the inherited scope is with 2 way data binding. The way JavaScript prototypes work is that writing to the rabbitCount property of the ChildController $scope will add a rabbitCount property to the ChildController $scope and effectively hide the parent property. $scope.rabbitCount no longer needs to follow the prototype chain to find a value. More details and pictures on this scenario in “The Nuances of Scope Prototypal Inheritance”.


Comments
Comments are closed.

My Pluralsight Courses

K.Scott Allen OdeToCode by K. Scott Allen
What JavaScript Developers Should Know About ECMAScript 2015
The Podcast!