Controllers in AngularJS

3 Sep by vichu

Controllers in AngularJS

Reading Time: 5 minutes

We saw how to create modules, but what do we do with them? So far, they have just been empty modules.

Let’s now take a look at controllers. Controllers in AngularJS are our workhorse, the JavaScript functions that perform or trigger the majority of our UI-oriented work. Some of the common responsibilities of a controller in an AngularJS application include:

  • Fetching the right data from the server for the current UI
  • Deciding which parts of that data to show to the user
  • Presentation logic, such as how to display elements, which parts of the UI to show, how to style them, etc.
  • User interactions, such as what happens when a user clicks something or how a text input should be validated

An AngularJS controller is almost always directly linked to a view or HTML. We will never have a controller that is not used in the UI (that kind of business logic goes into services). It acts as the gateway between our model, which is the data that drives our Application, and the view, which is what the user sees and interacts with.

So let’s take a look at how we could go about creating a controller for our vishalsrini module:

See the Pen Creating a module in angularjs by Vishal Srinivasan (@vishal_srini) on CodePen.0

We define a controller using the controller function that is exposed on an AngularJS module. The controller function takes the name of the controller as the first argument, which in the previous example is creatively named MainCtrl. The second argument is the actual controller definition, of what it does and how it does it.

But there is a slight twist here, which is the array notation. Notice that we have defined our controller definition function inside an array (this part -> [function() { … }]). That is, the first argument to the controller function on the module is the name of the controller (MainCtrl), and the second argument is an array. The array holds all the dependencies for the controller as string variables, and the last argument in the array is the actual controller function. In this case, because we have no dependencies, the function is the only argument in the array. The function then houses all the controller-specific code.

We also introduce a new directive, ng-controller. This is used to tell AngularJS to go instantiate an instance of the controller with the given name, and attach it to the DOM element. In this case, it would load MainCtrl, which would end up printing the console.log() statement.

Dependency Injection Syntax and AngularJS

The notation that we have used is one of the two ways in which we can declare AngularJS controllers (or services, directives, or filters). The style we have used (and will use for the remainder of the blog), which is also the recommended way, is safe-style of Dependency Injection, or declaration. We could also use:

angular.module(‘vishalsrini’, [ ])
.controller(‘MainCtrl’, function() {
});

and it would work similarly, but it might cause problems when we have a build step that minifies our code. We will delve into this more when we introduce Dependency Injection in future blog post.

Now, for our first AngularJS application with a controller, we are going to move the “hello world” message from the HTML to the controller, and get and display it from the controller. Let’s see how this would look:

See the Pen hello controller by Vishal Srinivasan (@vishal_srini) on CodePen.0

Yes, we only see “Hello AngularJS.” The “Goodbye” message is not printed in the UI.

Let’s dig into the example to see if we can clarify what is happening:

  • We defined our vishalsrini module as we saw before.
  • We created a controller called MainCtrl using the controller function on the module.
  • We defined the variable helloMsg on the controller’s instance (using the this keyword), and the variable goodbyeMsg as a local inner variable in the controller’s instance (using the var keyword).
  • We used this controller in the UI through the use of another directive: ngcontroller. This directive allows us to associate an instance of a controller with a UI element (in this case, the body tag).
  • We also gave this particular instance of the MainCtrl a name when we used ngcontroller. Here, we called it ctrl. This is known as the controllerAs syntax in AngularJS, where we can give each instance of the controller a name to recognize its usage in the HTML.
  • We then referred to the helloMsg and goodbyeMsg variables from the controller in the HTML using the double-curly notation.

By now, it should be obvious that variables that were defined on the this keyword in the controller are accessible from the HTML, but local, inner variables are not.

Furthermore, any variable defined on the controller instance (on this in the controller, as opposed to declaring variables with the var keyword like goodbyeMsg) can be accessed and displayed to the user via the HTML. This is basically how we funnel and expose data from our controller and business logic to the UI.

Getting Data to the HTML:
Changing ctrl.goodbyeMsg to goodbyeMsg in the HTML will not help either. We will not get the value of the goodbyeMsg variable from the controller to the UI without declaring it on the controller instance using the this keyword.

Anything that the user needs to see, or the HTML needs to use, needs to be defined on this. Anything that the HTML does not directly access should not be put on this, but should rather be saved as local variables in the controller’s scope, similar to goodbyeMsg.

$scope Versus controllerAs Syntax:
If you used AngularJS prior to 1.2, you might have expected the $scope variable to be injected into the controller, and the variables helloMsg and goodbyeMsg to be set on it. In AngularJS 1.2 and later, there is a new syntax, the controllerAs syntax, which allows us to define the variables on the controller instance using the this keyword, and refer to them through the controller from the HTML.The advantage of this over the earlier syntax is that it makes it explicit in the HTML which variable or function is provided by which controller and which instance of the controller. So with a complicated, nested UI, you don’t need to play a game of “Where’s Waldo?” to find your variables in your codebase. It becomes immediately obvious because the controller instance is present in the HTML.

Let’s take a look at one more example before we delve into how AngularJS works and accomplishes this:

See the Pen Controller one more example by Vishal Srinivasan (@vishal_srini) on CodePen.0

What has changed here?
  • We now have only one binding, which is in the ctrl.message variable.
  • There is a button with the label “Change Message.” There is a built-in directive on it, ng-click, to which we pass a function as an argument. The ng-click directive evaluates any expression passed to it when the button is clicked. In this case, we tell AngularJS to trigger the controller’s changeMessage() function.
  • The changeMessage() function in the controller sets the value of message to “Goodbye.”
  • Also, as good practice, we avoid referring to the this keyword inside the controller, preferring to use a proxy self variable, which points to this. The following note has more information on why this is recommended.

What we will see in play is that the app starts with “Hello AngularJS,” but the moment we click the button, the text changes to “Goodbye AngularJS.” This is the true power of data-binding in AngularJS. Here are a few things of note from the example:

  • The controller we wrote has no direct access to the view or any of the DOM elements that it needs to update. It is pure JavaScript.
  • When the user clicked the button and changeMessage was triggered, we did not have to tell the UI to update. It happened automatically.
  • The HTML connects parts of the DOM to controllers, functions, and variables, and not the other way around.

This is one of the core principles of AngularJS at play here. An AngularJS application is a data-driven app. We routinely say “The model is the truth” in an AngularJS application. What this means is that our whole aim in an AngularJS application should be to manipulate and modify the model (pure JavaScript), and let AngularJS do the heavy lifting of updating the UI accordingly.

Before we talk about how AngularJS accomplishes this, let’s take a look at one more example that will help clarify things.

This in JavaScript:

People used to languages like Java have trouble getting their heads around the “this” keyword in JavaScript. One of the insane and crazy (and downright cool) things about JavaScript is that the this keyword inside a function can be overridden by whoever calls the function. Thus, the this outside and inside a function can refer to two completely different objects or scopes. Thus, it is generally better to assign the this reference inside a controller to a proxy variable, and always refer to the instance through this proxy (self, for example) to be assured that the instance we are referring to is the correct one.

Byvichu

Love to code and Love to learn. A passionate technology lover who likes to sit with laptop even for weeks :D

Leave a Reply

Your email address will not be published. Required fields are marked *