A simple introduction to AngularJS, Part 4 – “Scope inheritance”

In the last part, we talked about how to set up to group different bits and pieces of a solution into units. We also talked about how to create controllers inside those modules. We briefly looked at creating a controller and using it to work with the scope object, and how, by using data binding, could update the UI in a more structured way.

In this part, we will take a deeper look into using controllers and scope. Mostly about how to use the scope to be honest. Controllers are all about functionality, while scope is about data binding. As I don’t have a special solution to build, there isn’t going to be a whole lot of functionality. There will be just enough functionality to show the stuff I am talking about…

Just as in the previous posts, I am going to start by creating a VERY simple HTML page. It looks like this

<!DOCTYPE html>
<html>
<head>
<title>A simple introduction to AngularJS - Part 4</title>
<script src="Scripts/angular.min.js"></script>
<script src="Scripts/app.js"></script>
</head>
<body>
</body>
</html>

As you can see, it is just an empty HTML page that includes 2 JavaScript files. One that contains Angular, and one where I will put my code…

The first thing I want to do, is to create a new module, and a simple controller. To do so, I add the following to my app.js file

angular.module('myModule',[])
.controller('myController',['$scope', function($scope) {
$scope.prop = 'Hello World';
}]);

Ok, that looks pretty familiar… Or at least it should if you have read the previous posts…

Now that I have a simple controller, let’s wire up the HTML by inserting an ngApp directive, and an ngController directive. And just to make sure it works, I will output the value of “prop” on the screen. Like this

<!DOCTYPE html>
<html data-ng-app="myModule" data-ng-controller="myController">
<head>
...
</head>
<body>
{{prop}}
</body>
</html>

Ok…loading that up in a browser outputs “Hello World” on screen as it should. It seems like things are working.

Let’s try adding one more really simple controller into the mix. Like this

angular.module('myModule',[])
.controller('myController',['$scope', function($scope) {
$scope.prop = 'Hello World';
}])
.controller('myOtherController',['$scope', function($scope) {
$scope.prop = 'Hello Mama';
}]);

So that is one more controller called myOtherController. It is is just as simple, and just sets the $scope’s prop property to “Hello Mama”. Let’s add it to the HTML like this

<!DOCTYPE html>
<html data-ng-app="myModule" data-ng-controller="myController">
<head>
...
</head>
<body>
{{prop}}
<div data-ng-controller="myOtherController">
{{prop}}
</div>
</body>
</html>

So what does this render? Well, exactly what you would have expected. One string that says “Hello World”, and one that says “Hello Mama”. And adding some CSS to make it more obvious, it looks like this

image

So the part with the white background will be the body, and thus controlled by the myController controller. The pink part is the div inside of it, controlled by the myOtherController controller…

Let’s add one more controller into the mix. It will be even simpler… It will do nothing at all. Like this

angular.module('myModule',[])
.controller('myController',['$scope', function($scope) {
$scope.prop = 'Hello World';
}])
.controller('myOtherController',['$scope', function($scope) {
$scope.prop = 'Hello Mama';
}])
.controller('myOtherOtherController',['$scope', function($scope) {
}]);

And then I add it to my HTML by adding a new div, setting the new controller as the controller, and databinding the prop property.

<!DOCTYPE html>
<html data-ng-app="myModule" data-ng-controller="myController">
<head>
...
</head>
<body>
{{prop}}
<div data-ng-controller="myOtherController">
{{prop}}
<div data-ng-controller="myOtherOtherController">
{{prop}}
</div>
</div>
</body>
</html>

Ok, so what is the result of this? Well, one would assume that we would see the strings “Hello World” and “Hello Mama” output on the screen. One time each… Cause the myOtherOtherController doesn’t set the property on its scope…right? Let’s see

image

(Once again with some CSS added to my page. The pale yellow, or pale golden rod as it is called, is the div that has the myOtherOtherController set…)

Wait…what… Why is there a “Hello Mama” inside the yellow? Well, that is actually very much to be expected… And here is the explanation.

When you declare an Angular app using the ngApp directive, you create a scope object. It is referred to as the “root scope”, which is actually always available to us as a service called $rootScope. If you do not declare any controllers in the page at all, this is the scope that will be used. But as soon as you declare a controller, a new scope will be declared. However, this scope inherits prototypically from the previous scope… I will get back to this in a minute.

So in our case, there will be a root scope declared for the application. Then, as we add the myController to the HTML element using the ngController directive, a new scope is created and injected into the controller. That new scope inherits prototypically from the root scope. Once again, I will come back to what that means in a minute…I promise!

So the white area in the image above is “bound” to that scope that was created an injected into the myController. Next, as I add the myOtherController, another scope is created and injected into the controller. This scope doesn’t inherit from the root scope, but from the scope that was injected into the myController, making this the scope bound to the pink area.

And finally, when adding the myOtherOtherController to the page, yet another scope gets created and passed to the controller. In this case, it inherits from the scope passed to the myOtherController. And this new scope is “bound” to the yellow area in the image…

So basically, every time you add a controller, a new scope is created. This scope is then set up to inherit prototypically from the “previous” scope, which is really powerful, and flexible, and sometimes really annoying…

Ok, so I promised to explain why I kept writing that they inherited the previous scope “prototypically”… If you are familiar with JavaScript’s prototypical inheritance, I suggest skipping this part. But if you aren’t a JavaScript developer, and have not heard about “prototypical inheritance”, I suggest quickly reading through my quick explanation. If you want a more detailed walkthrough, I suggest having a look on-line. Maybe here.

In classic object oriented programming, classes inherit from other classes, which means that the class inheriting from another class will get all of its features. The base class can hide some of it, but basically, the inheriting class will get a bunch of stuff pre-defined by the base class. This is the way most developers are brought up.

In JavaScript, and other prototypical, the inheritance looks a little differently. When you create an object, this new object will have a special property containing what is called the prototype. The prototype will be just an instance of another object, however it is treated a little differently. But basically, you can think of the prototype as just very special property on you instance…

In some JavaScript runtimes, you can modify and access the prototype property directly, in some it seems you can’t. But let’s ignore that…

So what does the prototype do? Well, whenever you ask an object for a member, the instance will look at itself and see if there is a member with that name. If there is, it returns it to you. If there isn’t, it asks the prototype for a member with the same name. The prototype then does the same thing. it looks at itself, and if it can’t find it, it asks its prototype. It does this recursively until it reaches the “root” object that has no prototype. If none of the instances along the way has a member with the corresponding name, undefined is returned.

So when I say that each scope “inherits” from its previous, or parent, scope “prototypically”, that is what I mean. When I ask the “current” scope for a member, it will look at itself first, and if it can’t find it, it asks the parent scope. It does so all the way up to the root scope…

This is a really powerful thing. It means that if we need functionality available throughout a page, we just declare it in our first controller, and then it will be available throughout the page.

It also means that out controllers can share data… However, you have to think about that just a bit… In the sample code, the controllers aren’t really sharing data back and forth. The child/sub controller will replace the value on the parent controller. But, that is because we are talking about modifying the actual member of the scope. If we were to modify a member on the scope member, we would actually be sharing data between the controllers…

What…? Que!? Ok…yeah, that might not have made a whole lot of sense without a demo. Let’s change the myController and myOtherController so that the share data. First of all, let’s declare a new property on the scope object in the myController. However, in this case, I won’t make it a simple string. I will make it an object. Like this

angular.module('myModule',[])
.controller('myController',['$scope', function($scope) {
$scope.prop = 'Hello World';
$scope.sharedProp = { val: 'value 1' }
}])
...
;

As you can see, the sharedProp is a complex property. It is an object with a property called val  with the value “value 1”.

Next, I will modify the myOtherController so that it changes the value of the val property. Like this

angular.module('myModule',[])
...
.controller('myOtherController',['$scope', function($scope) {
$scope.prop = 'Hello Mama';
$scope.sharedProp.val = 'Changed!!!';
}])
...
;

And finally, I will output the sharedProp.val property on screen, in both the body, and the first div. Like so

<!DOCTYPE html>
<html data-ng-app="myModule" data-ng-controller="myController">
<head>
...
</head>
<body>
{{prop}} {{sharedProp.val}}
<div data-ng-controller="myOtherController">
{{prop}} {{sharedProp.val}}
<div data-ng-controller="myOtherOtherController">
{{prop}}
</div>
</div>
</body>
</html>

Which results in

image

Hey…the sharedProp.val value is changed in both the parent and child scope… Hmm…

This is actually quite obvious when you start considering how prototypical inheritance works… In the myController controller, a property named sharedProp is added to the scope, containing an object with a single property called val.

In the body element, the databinding asks the current scope for a property called sharedProp, which it finds, and returns. The newly created object is returned, and the val property read and output on screen.

In the div element, a new controller is declared, and thus, a new scope is created. The child controller asks the injected scope object for a property with the name sharedProp. It doesn’t exist on the scope.

Remember, this is a new scope…

So instead, the scope asks its prototype, which happens to be the parent scope. The prototype, obviously has a property by that name as the parent controller just added it. So it returns it. The controller then changes the value of that object’s val property.

Remember, it is no changing a property on the same object that was added to the parent scope. It isn’t replacing the actual object in the new scope, but the property of the same object that is being used in the parent scope.

The databinding in the div then does the same thing as the other binding. Except that in this case, it asks the scope for a property with the name sharedProp, which doesn’t exist on the current scope. But once again, the prototypical inheritance kicks in, and it asks the prototype (the parent scope) for the same property. This returns the object we created in the myController controller. however, as we changed the val property on that object, the bound value will show “Changed!!!”.

The big surprise is the bound value in the body element. This shows the value “Changed!!!” as well. This is because as soon as we change a value on a scope, the databinding will refresh its value. As we change the val property on the sharedProp object, the databinding will refresh and show this new value…

So by using objects instead of simple types as properties on you scope objects, you can share data between scopes in the inheritance chain, which is really powerful, as long as you know what you are doing.

Ok, that was a pretty thorough walkthrough of scope inheritance. As it became a bit longer than I expected it to, I have decided to move the rest of the scope information to the next part, which will cover things like how to get notified when a scope value changes and ho to communicating between scopes using broadcast and emit.

So, that’s all for this time. Cheers!

Add comment