Understanding Controllers in AngularJS

The role of controllers in Angular is to expose data to the view via $scope, and to add functions to $scope that contain business logic to enhance view behavior. In other words, it is the responsibility of controllers to glue the Model (data) with the View.

Since $scope acts as an enabler in the controller’s ability to pass model to the view, lets first try to understand $scope.

One can imagine $scope as an object that links a controller to the view. When ever you add something to $scope, it can be displayed in the view with double curly braces ({{}}) or if it is a collection, we can use directives like ng-repeat to display them.

The following code is a sample AngularJS application that explains how controllers and scopes are used.



You can play with the above code using this plunker. There are a few important things to notice in the above code:

  1. ng-controller
  2. Nested controllers
  3. Mark up (double curly braces)
  4. ng-repeat
  5. Initializing $scope variables
  6. Adding functions to $scope (ng-click)


When we add an ng-controller attribute to an HTML element, it means that the code in between that HTML element will be bound to the controller mentioned in the attribute. In the example above, we have added MainCtrl as the controller for body tag. It means that all the elements within the body tag will have access to MainCtrl’s $scope object. Similarly, we have added “ContactsCtrl” to div element and all the elements with in the div will have access to ContactsCtrl’s $scope object.

Controllers can be assigned to view elements using ng-controller attribute or in the route config as explained in Understanding AngularJS Routes And Views With An Example

One thing to notice here is that the MainCtrl is like a parent controller and ContactsCtrl is its child. The general rules of inheritance apply here as well.

Nested Controllers

Nested controllers is when you define multiple controllers in a view using the ng-controller attribute. This enables us to take advantage of inheritance. In the example above, though we tried to display the name ({{name}}) bound to MainCtrl within the ContactsCtrl element, it still displays it because the element has access to it. Play with the Plunker to see how inheritance and nested controllers work.

Markup (double curly braces)

In AngularJS, the double curly brace notation {{ }} is used to bind expressions to elements. In the example above, we have bound the name as “GeekHours” to $scope in MainCtrl. To display that name in the view, we use markup.


The the above sample code, we displayed a list of contacts using an attribute ng-repeat.

ngRepeat is one of the most used AngularJS attribute. It iterates through an array of elements and binds the view with each element. So in our example it creates <li> tag for each item within contacts array. ngRepeat takes expression as argument. In our case “contact in contacts” where contact is user defined variable and contacts is an array within $scope.

Initializing $scope variables

We can initialize $scope with predefined values so that we can data when the view is loaded. In the example above, we have initialized contacts to hold two values and displayed them in the view using ng-repeat.

Adding functions to $scope (ng-click)

It is also possible to define functions on $scope and use the same in View. In our demo, we created a function add() on $scope and use it on Add button click:

The function add() is bound to Add button using an attribute ng-click. ng-click binds the click event on the button or link or any clickable element for that matter, with the function that is defined within $scope. So in this case, whenever the “Add” button is clicked, the add() method on $scope will be triggered.

In add() method we are adding (or pushing) a string in to the contacts array. This is the string that the user types in the text box. Note that we have bound the textbox using ng-model attribute. Thus, when ever a user types a string in the textbox and hits “Add”, the value in the textbox gets added to the contacts array and ultimately gets displayed in the view via ng-repeat.

Some best practices to follow when using controllers in AngularJS:

Use controllers to:

  • Set up the initial state of the $scope object.
  • Add behavior to the $scope object.

Do not use controllers to:

  • Manipulate DOM — Controllers should contain only business logic. Putting any presentation logic into Controllers significantly affects its testability. Angular has databinding for most cases and directives to encapsulate manual DOM manipulation.
  • Format input — Use angular form controls instead.
  • Filter output — Use angular filters instead.
  • Share code or state across controllers — Use angular services instead.
  • Manage the life-cycle of other components (for example, to create service instances).