There are two ways writing controllers in AngularJS

  • Function based
  • Class based

The first method is more popular. This format can be found in most angular tutorials.

Angular Function Based
(function (angular) {

    angular.module("MyApp").controller("HomeCtrl", function ($scope) {
        $scope.sayHello = function () {
            alert("Hello");
        }
    });

})(angular);
Angular Function Based Template
<div ng-controller="HomeCtrl">
    <button ng-click="sayHello()">Say Hello</button>
</div>

The second method is more elegant. You write the controller just as any other JavaScript class.

Angular Class Based Approach
(function (angular) {

    function HomeCtrl() {
    }

    HomeCtrl.prototype.sayHello = function () {
        alert("Hello");
    }

    angular.module("MyApp").controller("HomeCtrl", HomeCtrl);

})(angular);

Angular does not support the class based approach by default. You need to modify the template.

Angular Class Based Template
<div ng-controller="HomeCtrl as ctrl">
    <button ng-click="ctrl.sayHello()">Say Hello</button>
</div>

The big gain using the class based implementation is that it allows you to use a base controller class.

BaseCtrl class with $destroy and onDispose
var MyApp = MyApp || {};

MyApp.BaseCtrl = (function () {

    function BaseCtrl($scope) {
        var me = this;

        me.$scope = $scope;

        me.$scope.$on("$destroy", function () {
            me.onDispose();
        });
    }

    BaseCtrl.prototype.onDispose = function () {
        var me = this;
        console.log(me.name + ".dtor");
    }

    return BaseCtrl;
})();

Common methods required by all controllers should be stored in the BaseCtrl class. In the sample above the $destroy event and call the onDispose method are added. This allows the actual controller to override onDispose method without registering to Angular events which produces cleaner code.

HomeCtrl implementing the BaseCtrl
(function (BaseCtrl) {
    function HomeCtrl($scope) {
        BaseCtrl.call(this, $scope);
    }

    HomeCtrl.prototype = Object.create(BaseCtrl);

    HomeCtrl.prototype.onDispose = function () {
        console.log("HomeCtrl.dtor");

        BaseCtrl.prototype.onDispose.call(this);
    }

    HomeCtrl.prototype.sayHello = function () {
        alert("Hello");
    }

    angular.module("MyApp").controller("HomeCtrl", ["$scope", HomeCtrl]);
})(MyApp.BaseCtrl);

In Angular projects you can implement a method named resolve inside the BaseCtrl which knows how to resolve a dependency on demand without specifying it during controller registration. This method can simplify code when having a controller with long dependency list.

Comments