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#.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Gabriel Schenker

Gabriel N. Schenker started his career as a physicist. Following his passion and interest in stars and the universe he chose to write his Ph.D. thesis in astrophysics. Soon after this he dedicated all his time to his second passion, writing and architecting software. Gabriel has since been working for over 12 years as an independent consultant, trainer, and mentor mainly on the .NET platform. He is currently working as chief software architect in a mid-size US company based in Austin TX providing software and services to the pharmaceutical industry as well as to many well-known hospitals and universities throughout the US and in many other countries around the world. Gabriel is passionate about software development and tries to make the life of developers easier by providing guidelines and frameworks to reduce friction in the software development process. Gabriel is married and father of four children and during his spare time likes hiking in the mountains, cooking and reading.
This entry was posted in AngularJS, introduction. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Alper

    Minor suggestion: You may want to consider changing the css class name “scope” to make it clear that there is no relationship between angular provided $scope and stylesheet class scope.

    • Jaminyah

      Great suggestion. I also has the same thought and so changed mine from “scope” to “controller”.

  • AbelebA

    Started reading your posts on AngularJS this morning and I’m hooked already. Keep them coming and please continue making them simple and easy to understand.
    Thanks for sharing…

    • Gabriel Schenker

      That’s my plan :-)

    • gabrielschenker

      That’s my plan :-)

  • Boufleuhr

    Your posts are outstanding! This is the best way to teach something about tech that I have ever seen, congratulations!

    • Gabriel Schenker

      Thank you for the flowers. Much appreciated!

    • gabrielschenker

      Thank you for the encouraging feedback; much appreciated!

  • Colm

    Might be worth mentioning, in the newest version of Angular, ngRoute isn’t part of the core anymore, I had trouble with that trying to follow this post. You need to include a reference to angular-route.js and add it as a dependency like:

    var app = angular.module(‘myApp’, ['ngRoute']);

  • Pingback: Great 8-part AngularJS tutorial from Gabriel Schenker | Andy Poots’s Weblog

  • Goran Obradović

    Great series, for me these posts were main motivator to start really dedicating time for learning angularjs and starting to use it to learn through experience. And I can see that it addresses a lot of pain that I experienced when I was implementing “directives” using asp.net mvc with metadata customization and generation of specialized knockout bindings. Even when things work out perfectly, what stays there is far less documented than angular, and I just want to thank you for writing this series, it hooked me on angular and it will improve products I make.

  • Jonathan

    Thanks so much for taking the time to break all this down. My hands-on introduction to AngularJS was by way of the ionic framework, so these articles are helping me to fill in the gaps in my knowledge.

    • gabrielschenker

      Am happy to hear that!

  • Roma-Sem

    Gabriel, THANK YOU for great job! It really helped me to fill the gaps and now a lot things became clear. I’ve started to like AngularJS and such things can only happen when you’re getting relaxed cause you simply understand it! :)

    Thank you!