Base Controller with AngularJS

1 בינואר 2015

There are two ways writing controllers in AngularJS

  • Function based
  • Class based

For some reason, the first method is more popular (probably, because Angular's tutorials are written that way)

(function (angular) {

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

})(angular);

And the corresponding template

<div ng-controller="HomeCtrl">
    <button ng-click="sayHello()">Say Hello</button>
</div>

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

(function (angular) {

    function HomeCtrl() {
    }

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

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

})(angular);

However, Angular does not support this style out of the box. You need to update the template

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

From my POV the big advantage using the later implementation is that it allows you to use a base controller class

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;
})();

The BaseCtrl is a great place to store common methods required by all controllers. In my sample above I register to the $destroy event and call the onDispose method. This allows the actual controller to override onDispose method without registering to Angular events which creates cleaner code

(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 my Angular projects I 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. Read my next post for more details about this technique …

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

2 comments

  1. Jason Watmore6 בינואר 2015 ב 2:27

    That's quite a lot of code just to implement a base controller, I prefer this more simple method – http://jasonwatmore.com/post/2014/03/25/AngularJS-A-better-way-to-implement-a-base-controller.aspx

    Reply
  2. Ben Nadel7 בינואר 2015 ב 2:39

    It's definitely an interesting idea. At this point, however, I've been staring at Functions for so long, they just make sense 😀 I'm not sure that I have sufficient friction. I've been trying to move shared functionality out to services and other objects.

    You should see some of the insanity I have in my early AngularJS code that tried to abstract things in weird ways. Very hard to follow.

    Reply