Thursday, 15 May 2014

AngularJS–Part 3, Inheritance





                                    

In this post I want to discuss the aspect of controller inheritance.

JavaScript is not an OO language

Once again it is important to remind ourselves that JavaScript is not one of the classical OO computer languages. Yes, we can write object oriented code in JavaScript but this is certainly not the best language to do so. Much more should we embrace the functional aspect of JavaScript. Many of the popular libraries do this. jQuery seems to be the most prominent example and also AngularJS follows this line clearly. In this regard when talking about inheritance we should not expect the same behavior as we know from C# or Java, which are two of the most popular OO languages.

Controller inheritance

What can I expect then from controller inheritance? Let’s look at a sample right away. We create two controllers, a parent and a child controller. We can add the necessary code to the app.js file of our sample application. Let’s just start with the definition of the empty controllers
image
Whenever we define a new controller we give it a name and add it to the controller collection of our Angular app. The controller itself is a function which wraps the data (or the model) and the logic which constitute the controller. So far our two new controllers are just empty hulls.

Simple variables

Let’s start by defining a simple variable title in the parent controller and content in the child controller. It is important that these are simple (string) variables and not objects.
image
Now we need a view where we use these two new controllers. Let’s create a new HTML page called part3.html. As we have learned in the previous post a controller manages part of a view. Often this is a div tag containing the Angular directive ng-controller whose value is set to the name of the controller. To make the child controller ChildCtrl a true child of the parent controller ParentCtrl the area managed by the parent needs to wrap the area managed by the child controller, or said differently, the child controller must be wrapped by the parent controller. This is a typical layout
image
As you can see, the outer parent div wraps the inner child div . Make sure you don’t forget to also add the ng-app directive referencing our application called myApp. Usually we add the directive to the body tag. Also make sure you have referenced the Angular JavaScript angular.js file and our application JavaScript file app.js. Furthermore we also need our app.css file containing the layout defined so far. I have added the scope class to the two div tags to be able to visually see the parent and the child context or scope on the view.
Now let’s add some input tags that bind to the title and the content values defined in the controllers. We add
  • an input bound to title to the parent div
  • an input also bound to title (defined in the parent controller) to the child div
  • an input bound to content to the child div
image
Save and open the view part3.html in your favorite browser. You should see something similar to this
image
We can nicely see how the child area is nested inside the parent area. We can also see how the binding works as we see the texts displayed as we have defined them in the controllers. It is important to note how the child inherits the title value from its parent.
Now type something into the first input box (owned by the parent controller) and observe how the text in the input box owned by the child controller changes too.
image
That’s what we expect, right? But now to the interesting part, change the text in the input box in the child area and observe the outcome.
image
Apparently my changes entered in the child area did not affect the value displayed in the parent area! And if you now change the value in the parent area again, the child value won’t change anymore.
What happened here? The title variable – a simple variable of type string – was defined on the parent $scope. At first the child inherited this value. But then, once the user changes the title value in a control bound to title located in the child area Angular creates a new variable title on the child $scope and from this moment on child and parent title are decoupled. Each controller has its own instance.

Complex types

If we want to avoid this behavior of having a local instance in the child scope we need to use complex types, that is objects. Let’s change our definition in the parent controller as follows
image
Our title is now a property of a variable model which in turn is an object. We also have to adjust our binding in the view as shown below
image
If we refresh the browser and play with the two input boxes we can verify that this time model.title does not get redefined on the client scope and remains a property of the parent scope inherited by the child scope. This is a very important difference in behavior that we need to be aware of.
Now the clever person might ask: “And what happens if I reset the model object all together from the client $scope?”. Ah, good question I say to myself. Let’s try it. Add a button to the child div and bind the click event to a function called setModel.
image
define the setModel on the child $scope as follows
image
Refresh the browser and verify that after clicking the button once again the two input boxes are disconnected. We have now our own instance of model defined on the child $scope.

Inheriting functions

Now we want to explore how functions are inherited. For this purpose we define a function greet on the parent $scope. This function when called just shows an alert box greeting the user.
image
We then add a button to the parent  and one to the child area and bind both click events to this newly defined function
image
Please refresh the browser and confirm that no matter which of the two buttons you click the application will always show the same alert box. With this we have proven that a child controller can indeed inherit functions from its parent controller.
But what happens if we redefine the function greet on the child $scope? Let’s try and define such a function which shows an alert box with a different text.
image
Ok, when doing that we realize that now the button defined in the child area displays the new alert message. This means that we have just broken the inheritance chain and the child has now its very own definition of a function with name greet.

Summary

We have discussed how inheritance works in the context of Angular controllers. In Angular we talk of a child controller if the view area that is managed by the child controller is nested inside the view area that is managed by the parent controller. Simple values (e.g. strings, numbers, booleans, etc.) are only inherited by a child controller as long as they are not redefined on the child $scope. Properties of object on the other hand are always inherited by the child controller as long as we do not redefine the whole object on the client $scope. A child controller also inherits functions defined on the parent controller as long as they are not redefined on the child $scope.
In the next post I will have a look on how we get data from a server by using the $http service provided by AngularJS.


AngularJS–Part 2, the controller

                    

Introduction

This is a series of posts to describe our approach to slowly migrate a Silverlight based client of a huge and complex LOB  to an HTML5/CSS3/JavaScript based client. These posts report on the lessons learnt and are meant to be used as a reference for our development teams. The first part of this series can be found here.
So far we have talked about the view and the model in the last post but we have not yet introduced a controller. A controller contains the (presentation or workflow) logic of our Web client. It is written in JavaScript. AngularJS strongly encourages us to separate concerns and put all logic/code into controllers and keep the view (the html page or html fragment) free from any JavaScript. The model on the other hand is a representation of the data we need to display or change through the user’s input.
We need a place where to put our code and thus we add a new JavaScript file app.js to our folder HelloAngular. We reference this file in our html page after referencing the angular.js file.*)
image
*)I specifically mention this since it happened more than one time to me that I introduced a new file with JavaScript code and forgot to reference it in my view, leaving me wonder why my app would not work as expected…

The application

Now it is time to define an (AngularJS) application. Angular defines modules and for the moment our app is an angular module. We can do this as follows
image
Here my application is an Angular module and is called myApp. The second parameter in the module definition represents the dependencies**) that my module/app has. In our sample it is an empty array meaning that we have no dependencies so far.
**) Angular uses dependency injection similar to what we know from a typical C# application where we use an IoC container.

The first controller

Ok, finally we are ready to define a first controller. We add the controller to the controller collection of our Angular application as follows
image
As a developer used to code with an OO language like C# or Java we have to be aware of the fact that JavaScript is not an OO language. Yes, we can use it in a similar way as an OO language but this is definitely not its strength. Rather should we embrace the functional aspect of the language and code accordingly.
Most modern JavaScript libraries like JQuery and AngularJS do so and one consequence we see right away in the above definition of our first controller called FirstCtrl. In looking at the name of the controller we can identify two conventions typically used in Angular.
  • Names of Controllers are in Pascal Case
  • Names of Controllers have a suffix Ctrl
The actual controller is a function wrapping all the code and state that make up the controller. In the above snippet we have a function with no parameters. As we will see below usually a controller (constructor) has one to many parameters that will be provided to the controller via dependency injection.

Data and scope

Lets first define some data in the controller. We want to define an object with properties whose values can be data bound to the view and whose values can also be programmatically set or changed in the controller. Data in a controller is usually defined on the scope of a controller. Let’s do this
image
But wait a second, what is a scope and how do I get a scope?
A scope as defined by Wikipedia is the part of the program in which a name that refers some entity can be used to find the entity. Here we talk about data, but the same also applies to functions. In JavaScript functions are treated much the same way as data. As we will see when defining an Angular controller we will define the data it deals with and the logic it encapsulates on the scope of the controller.
I get my scope via dependency injection, that is, it is provided to me by Angular. Thus I can just change the definition of my controller as such
image
Note the parameter $scope of the function. Also note that all Angular services or providers are prefixed with a $ sign.
In the above snippet we define an object model on the $scope which has two properties firstName and lastName. The properties are initialized with according values. When we now refresh our page we would expect that the property firstName of the model object is bound to our view and thus the view displays the value “Gabriel”. Try it out… Ok?
It didn’t work. Why not? It’s not working because we did not yet tell Angular to use our application myApp and with it the controller FirstCtrl. Let’s do this then. First we add the name of our application as a value to the ng-app directive which we had previously added to the body tag.
image
then we wrap our little html fragment with the input and the div tag into another div which contains an ng-controller directive. The value of the directive is the name of the controller we have defined.
image
If we now refresh the page our binding works perfectly and the initial value as defined in the controller is displayed both in the text input an the div. And with this we have shown that the binding works from the controller to the view. But does it also work in the opposite direction? To show this we need to add some logic to the controller.

Logic

Let’s add a button to the view whose click event we bind to a function defined in our controller. In the function we just show an alert with the current content of the firstName property of the model object. So let’s first add the logic to the controller. As I mentioned above functions are defined on the $scope of the controller similar to the model or data. We can do this just after the definition of the model.
image
Now we add the button to the view. We use the ng-click directive to bind the click event of the button to the clickMe function in the controller.
image
Note that this is different from the traditional way of doing things, where we would have used the onclick attribute of the button tag to bind the click event to some JavaScript code in the view. When we run the application and enter say “Jack” into the input box and then click on the button an alert box will popup greeting Jack as expected.
image
As trivial as this example seems and as easy as the code looks it is still a quite important concept that we have explored here. I have shown so far how we can data-bind between the model (defined in the controller) and the view as well how we can bind user actions which trigger events on the view to functions defined in the controller.
We are of course not limited to parameter-less function calls. Instead of using the $scope in the clickMe function to get the name we can as well define a name parameter on the function and show its content in the alert box
image
The call in the view has then to be adjusted and we have to pass the model.firstName as a parameter in our function call
image

Multiple controllers per view

We can have multiple controllers per view governing different areas of the view. In such a scenario each controller manages a fragment of the overall page. To visualize this lets define a style that we put on each area managed by a controller. Please add a new file app.css to your folder HelloAngular and reference it from the html page.
image
Add a style .scope to the app.css. This style basically draws a black border around the area which is governed by a single controller.
image
Now duplicate the html fragment in the view managed by the FirstCtrl controller and add a class scope to each of the two fragments.
image
Each of the two html fragments will now be managed by its own instance of the FirstCtrl controller. These two fragments are completely independent from each other as you can verify by yourself when refreshing the view in the browser
image
We can even nest controller instances as shown in the following sample
image
and the according (complete) html is shown here
image

Summary

In this post I have introduced the AngularJS controller. With this we have discussed all three pieces of the MVC (model-view-controller) pattern that is commonly used when building an Angular app. I have shown how we can bind data to the controller and we have proven that the data-binding is indeed a two way binding. We have also learned how to bind an event of a view control (such as the click event of a button) to a function defined in the controller. Furthermore we have briefly discussed how we can have multiple instances of a controller managing different, possibly nested parts of the view. In my next post I will look a bit more closely into the inheritance between controllers and child controllers and compare this JavaScript type of inheritance with the familiar one used in C#.