Thursday, February 20, 2014

angularjs Controller in detail

What is angularjs controller, here is a quote from angularjs website

In Angular, a Controller is a JavaScript constructor function that is used to augment the Angular Scope.
So it is used to augment scope:
  • add properties to scope
  • initialize scope
  • add behaviors to scope
The controller name is like a semantic class name or tag for the piece of function added to scope
So does it matter it is constructor function or regular function? No. It does not matter in almost all situations. You usually do not use the this keyword in constructor function. After the scope is augmented,  the controller object is forgotten. The controller object created by angularjs from this constructor function is never referred again. It is actual an empty object without any property or function.
But it is actually not empty and used in two cases in angularjs. It is the FormController and ngModelController. These two controllers have a bunch of methods and properties themselves. These methods coordinates with each other to provide validation for inputs.

Get hold reference of  controller object

So how can you find out these controller objects? Required controller can be specified when directive is designed. The needed controller is available for use in link function.
instApp.directive('fxPropeditor', function($compile,fxTemplates){
    return {
        require:"^form", //need to work under form controller
        template: "<div/>",
        controller : myController,
        link : function(scope, iElement, iAttrs, form, transcludeFn) {

In the above example, require property tells angularjs a form controller is needed in parent dom. In the link function, the form controller object is available from injection. It can be used to set form validation state or add extra custom form control.

Retrieve controller object afterward.

The form control sets itself to scope like this
in controller constructor function. The formname is the string literal of name property.  One can find out form controller from scope using formname. But other controllers usually do not add itself scope.  Moreover form controller is not added to scope if there is no name for form. For example, given html like this
<form ID="TEST">
            <input type="text" data-ng-model="test"/>

The form controller will not be attached to scope since there is no name attribute for <form>.  Angularjs attaches controller object to DOM node using data() under the hood.  You can always inspect controllers associated with an element using the data().  angular.element(document.getElementById("TEST")).data().  Controller  can be retrieved like this like this angular.element(document.getElementById("TEST")).controller("form").

Controller and Scope

Is there a new scope for every controller object? No. The relation between controller object and scope depends on the directive.  The fxPropeditor directive example above will create a new myController controller object. But no new child scope is created since this directive does not have a scope property. The is also true for form controller.  On the other hand, ngController always creates a child scope.
var ngControllerDirective = [function() {
  return {
    scope: true,
    controller: '@',
    priority: 500

since it explicitly requests a new child scope.