Community Post

Angular JS: Scope Demystified

Nitish Kumar

The heart of binding in angular js is something known as $scope, essentially this is a variable which angular is watching for any changes, and as soon as the $scope changes, it would update the view.

Lets look at a very simple example of binding.

    <div ng-controller="myController">
    Hello {{name}}
    </div>

So essentially any thing we put in $scope would be updated, should not be that hard right.

We still need some javascript code which updates the model but it has to do it in a way that angular would know when the update happens. This is a little tricky part of angular, so if we update a $scope from a code outside angular, the view would not get updated, i.e from a setTimeout function because angular is not watching the scope variable then.

We need an angular managed function which can update the $scope and when that function is done, angular would run the digest cycle again. This managed function is a Controller.

Lets try to dig a bit deeper and understand what is happening here, so we would open the console tool in chrome and select body tag in html, then go to console and type

$($0).scope()

Essentially $0 is alway the last selected item in chrome dev tool, I find that very useful. You can try and use $1, $2 and so forth..

This is how your scope should look like.

Scope

if you see the firstName and lastName is set to appropriate values. If you notice each scope has an id, in this case the id is 2, and it also has a $parent attribute, if you open the $parent the id should be 1, also there is a property called _proto_ , if you want to know more what this property is, read Understanding Prototype

So essentially each $scope is prototype inherited from parent $scope and each $scope has a reference to $root which is the rootScope and parent of all the $scope. If you type

$($0).scope().$root.$id

it should print 1 which is also the parent of our controller scope as we saw.

Now let try to do something funky.. :)

We would try to change the scope variable from chrome console and see if that changed the view. Lets try to type following in console and see.

$($0).scope().firstName = 'Jane'

The view did not change, right? So what happened ? Since we modified the scope variable outside angular managed code, angular still does not know that the variables have changed. So we would need to tell angular that variables have changed and we would do this by calling $scope.$digest() so lets change the above code to

$($0).scope().firstName = 'Jane'
$($0).scope().$digest();

And voila! our view changed.

Nested Scope

Lets try to add a list of names to our page using ng-repeat. Lets add a list of names of our controller.

 $scope.items = [
        {name:'Eddard Stark'},
        {name:'Robb Stark'},
        {name:'Sansa Stark'},
        {name:'Arya Stark'},
        {name:'Brandon Stark'},
        {name:'Rickon Stark'},
        {name:'John Snow'}

    ];
<ul>
    <li ng-repeat="i in items">{{i.name}}</li>
</ul>

You can see the above code at Plunker

If you are not a Game Of Thrones fan, you can assume they are just some random names. Now the ui should render a list of names as given below, lets check the scope again, this time we would pick the li elements and check the scope variable applied to them.

<ul>
    <!-- ngRepeat: i in items -->
    <li ng-repeat="i in items" class="ng-binding ng-scope">Eddard Stark</li>
    <li ng-repeat="i in items" class="ng-binding ng-scope">Robb Stark</li>
    <!-- end ngRepeat: i in items -->
    <li ng-repeat="i in items" class="ng-binding ng-scope">Sansa Stark</li>
    <!-- end ngRepeat: i in items -->
    <li ng-repeat="i in items" class="ng-binding ng-scope">Arya Stark</li>
    <!-- end ngRepeat: i in items -->
    <li ng-repeat="i in items" class="ng-binding ng-scope">Brandon Stark</li>
    <!-- end ngRepeat: i in items -->
    <li ng-repeat="i in items" class="ng-binding ng-scope">Rickon Stark</li>
    <!-- end ngRepeat: i in items -->
    <li ng-repeat="i in items" class="ng-binding ng-scope">John Snow</li>
    <!-- end ngRepeat: i in items -->
</ul>

If you see now the scope should have changed.

angular scope

This is the scope of second li child which has an id 11 and has the parent as id 2 which was our original controller scope. Not only that, every li should have a different scope each extending from our controller scope.

This is because we used the directive ng-repeat, each instance of directive gets assigned a new scope which extends from the current directive scope. So our scope id 2 is essentially a scope assigned to the ng-controller directive and each of ng-repeat as shown in the html above gets a new scope derived from parent scope.

If you like the article, you can read more on Angular on my site at ScaffoldThis

Nitish Kumar

Founder @ http://www.scaffoldthis.com, Full stack geek, fiddling with technologies for more than 14 years. Thinks in Java, has a long love hate relation with web dev and JavaScript.