Check out these related webinars…

1. Controller Main Responsibilities

  • In AngularJS, controllers have the following responsibilities:
    • Set up the initial state of the model. Usually, a controller retrieves the data from a remote web service.
    • Handle user input events. This usually involves validating the input and invoking a remote web service to complete a task.
    • Observe and react to changes to the model objects.
  • Primary use of controllers is to act as a liaison between the view and the model layers. For larger applications, avoid doing any complicated business logic directly from a controller. Move such activities to services and use services from controllers.
  • In a Single Page Application, controllers contain the logic to control the page transition sequence.

2. About Constructor and Factory Functions

  • AngularJS uses two types of functions to create instances of artifacts like controllers and services.
  • A constructor function – a standard concept in JavaScript – is used as a template to create a new object at a later time.
     var Circle = function(r) {
     this.radius = r;
     }
     var c1 = new Circle(10);
    

     

  • A factory function creates the object and returns it.
     var CircleFactory = function(r) {
     return {
     radius: r
     }
     }
     var c1 = CircleFactory(100);
    

     

  • Not all artifacts can be created using both types of functions. Details are covered in the specific chapters for the artifacts.

About Constructor and Factory Functions
Before we get into the details of controllers, we need to know about constructor and factory functions. They will play a role throughout this course. They are two different ways of creating objects. AngularJS uses them somewhat inconsistently. For example, a controller can only be created using a constructor function. But, AngularJS provides ways to create a service using either constructor or factory.

3. Defining a Controller

  • A controller is defined by registering a constructor function using the controller() method of a module.
    angular.module("SimpleApp", [])
     .controller("MyCtrl", function() {});
    
  • The initialization function can receive injected objects as parameters.
    angular.module("SimpleApp", [])
     .controller("MyCtrl", function($scope, $http) {});
    
  • The constructor function is where the initial state of the model is set up.

4. Using the Controller

  • To use a controller in a page, use the ng-controller attribute with a DOM element.
  • That DOM element will serve as the root of the hierarchy that will be managed by the controller instance.
  • A new instance of the controller is created for each declaration using ng-controller using the constructor function.
    <div ng-app="SimpleApp">
     <div ng-controller="MyCtrl"> ...</div>
     <div ng-controller="MyCtrl"> ...</div>
    </div>
    

5. Controller Constructor Function

  • This is a JavaScript constructor function that is used to create a new instance of a controller. This is where we set up the initial model data.
  • There are two different ways to store model data:
    • Using the scope of the controller instance. This is the prevalent approach and we will learn about it first.
    • As properties of the controller instance.
  • The scope of a controller can be obtained by injecting the $scope object. Example:
    .controller("MyCtrl", function($scope) {
     $scope.product = {
     productId: 1001,
     title: "Baseball gloves",
     price: 23.99
     }
    });
    

• Once the model data has been set up, it can be bound to DOM elements:

<div ng-controller="MyCtrl">{{product.title}}</div>

6. More About Scope

  • A scope is an object where you can store model objects as properties.
  • Every module instance gets its own scope. This can be accessed by injecting the $rootScope object.
  • Every controller instance gets its own scope that can be accessed by injecting the $scope object.
  • The $scope of a controller inherits from the $rootScope using prototype chaining. Which means, objects added to the $rootScope are visible to the child $scope.
  • A controller can contain other child controllers. The $scope of the child controllers will inherit from the parent’s $scope using prototype chaining.

Notes:
The $scope object is an instance of the Scope framework class which provides methods for controlling scope’s lifecycle, event-propagation, and other infrastructure facilities.

7. Example Scope Hierarchy

 angular.module("SimpleApp", [])
 .run(function($rootScope) {
 $rootScope.message = "Hello";
 })
 .controller('ParentCtrl', function($scope) {
 $scope.message = $scope.message + " World.";
 })
 .controller('ChildCtrl', function($scope) {
 $scope.message = $scope.message + " How are you?";
 });

Example Scope Hierarchy
In the example above, the run function adds a string object to the scope of the module using the property named “message” with the value “Hello”.

The constructor function of the ParentCtrl controller first reads the message property of $scope. This will cause JavaScript to walk up the prototype chain and get the value from $rootScope. Next, we define a property of the $scope called message. At this point, the $scope object gets its own copy of the property with value “Hello World”.

The constructor for ChildCtrl reads the message property of $scope. If we use this controller as a child of ParentCtrl, then we will read “Hello World”. We then add a message property to $scope with the value “Hello World. How are you?”.

8. Using Scope Hierarchy

 <div ng-app="SimpleApp">
 {{message}} <!-- Root scope -->
 <div ng-controller="ParentCtrl">
 {{message}}
 <div ng-controller="ChildCtrl">
 {{message}}
 </div>
 </div>
 </div>

 

 

9. Modifying Objects in Parent Scope

  • The way JavaScript prototypes work, you can read a property from the parent object if the property is not defined in the child. However, if a child adds the property, it is added to the child and not to the parent.
  • This means, in order to be able to change a value in the parent scope, you must add it as a JavaScript object rather than a primitive type like String.
    .controller('ParentCtrl', function($scope) {
     $scope.message = "Hello World.";
     $scope.product = {
     title: "Baseball gloves"
     };
    })
    .controller('ChildCtrl', function($scope) {
     $scope.message = "Hello Moon."; //Doesn't update parent
     $scope.product.title = "Volleyball net"; //Updates parent
    });
    

 

Modifying Objects in Parent Scope

In the example, we assume that ChildCtrl will be used as a child of the ParentCtrl controller.

When ChildCtrl sets the message property, the property is added to the scope of ChildCtrl. It doesn’t change the property in the parent scope.

When we update $scope.product.title, system first looks up $scope.product from the parent. We then update the title property of that object. Thusly, we directly modify the parent’s scope.

10. Modified Parent Scope in DOM

 <div ng-controller="ParentCtrl">
 {{message}} {{product.title}}
 <div ng-controller="ChildCtrl">
 {{message}} {{product.title}}
 </div>
 </div>

 

 

  • The child has successfully updated parent scope’s product.title but not the message property.
  • Since all controller instances are created before the DOM is rendered, we never get to see the original value of product.title – “Baseball gloves”.

11. Handling Events

  • Add event handling functions to the $scope as properties.
    .controller("TestCtrl", function($scope) {
     $scope.message = "Hello ";
     $scope.popIt = function(msg, planet) {
     alert(msg + planet);
     }
    });
    
  • Register the event handler in DOM using ng-event_name attribute.
    <div ng-controller="TestCtrl">
     <button
     ng-click="popIt(message, 'World')">Test</button>
    </div>
    
  • Event handler methods can take any number of arguments that are either constants or properties of the scope.
  • Other event registration attributes include: ng-blur, ng-keydown, ng-mouseenter, etc.

Handling Events
An event handling function is added to a controller’s scope and is registered in the HTML markup.

An event handling function can take parameters which are supplied at the point of registration in the HTML markup. You can supply constants (like ‘World’ in the example above) and properties of the scope (like message above).

If you need to attach a click event handler for an element, you should disable reloading of the page when the user clicks the link. This is done by supplying an empty href attribute. For example:
Click me

12. Another Example for Event Handling

 .controller('TestCtrl', function($scope) {
 $scope.className = "normal";
 $scope.activate = function() {
 $scope.className = "active";
 }
 $scope.normalize = function() {
 $scope.className = "normal";
 }
 });

 <style>
 .normal {
 background: green
 }
 .active {
 background: red
 }
 </style>

 <div ng-controller="TestCtrl" 
 ng-mouseenter="activate()" ng-mouseleave="normalize()">
 Hello there!
 </div>

Another Example for Event Handling
In the example above, the div tag will toggle between red and green background as the mouse enters and leaves it.

13. Storing Model in Instance Property

  • An alternative way to store model data is to add them as properties of the controller instance.
    .controller('TestCtrl', function() {
     this.message = "Hello World";
     this.showIt = function() {
     alert(this.message);
     }
    });
    
  • Declaring the controller in DOM requires a slightly different approach.
    <div ng-controller="TestCtrl as test">
    I will say {{test.message}}
    <button ng-click="test.showIt()">Test</button>
    </div>
    

14. Summary

  • An AngularJS controller’s primary job is to:
    • Initialize model data from its constructor function.
    • Handle DOM events as the user interacts with the page.
  • There are two ways you can set up the model data:
    • Using the controller’s scope.
    • Use properties of the controller object.
  • The scope of a controller inherits from the root scope of the module using the prototype chain. The same goes for a child controller embedded inside a parent controller.

Related Webinars