OdeToCode IC Logo

AngularJS Abstractions: Modules

Wednesday, May 1, 2013

Continuing from the last post, a module in AngularJS is a place where you can collect and organize components like controllers, services, directives, and filters. We'll talk about the "when & why" of creating a module in a later post. This post will focus on the API to create a module, and get a reference to an existing module. Stimulating topic, eh?

The proper way to create a module is to use the angular.module method passing at least the module name, and an array naming all the dependencies of the module  (or an empty array if there are no dependencies).

angular.module("patientApp.Services", []);
angular.module("patientApp.Controllers", []);   
angular.module("patientApp", ["patientApp.Services",
                              "patientApp.Controllers"]);

The above code actually creates three modules – patientApp.Services, patientApp.Controllers, and a patientApp module that depends on the previous two modules. I like to have all this code centralized in one place for easy management.

The following code defines the three modules, then comes back and adds a "run block" to the patientApp module (a run block is a piece of code that Angular will invoke once the module is assembled and configured).

(function () {
    "use strict";

    angular.module("patientApp.Services", []);
    angular.module("patientApp.Controllers", []);   
    angular.module("patientApp", ["patientApp.Services",
                                  "patientApp.Controllers"]);

    var app = angular.module("patientApp");
    app.run(["$rootScope", function ($rootScope) {
        $rootScope.patientAppVersion = "0.0.0.1";
    }]);
    
}());

Note the call to angular.module("patientApp") does not pass a second parameter with required module names, doing so would recreate the module and destroy anything already registered inside. Calling angular.module with just the module name will give you back a reference to an existing module so you can continue adding run blocks, services, directives, and other components into the module.

Somewhere else in the same file, or in a separate file, another block of JavaScript code might add an "alerter" service to the 'patientApp.Services' module (I know we haven't talked about services yet, but we will, and the short summary is that a service can carry out a specific task, like communicate over the network, and a service typically contains code you want isolated for testability or to obey the single responsibility principle).

(function () {
    var alerter = function () {
        return {
            alert: function (message) {
                // ... do something alerty
            }
        };
    };

    angular.module("patientApp.Services")           
           .factory("alerter", alerter);
}());

The API and terminology around services in Angular is unfortunately confusing and sometimes misleading, but we'll talk about that, too. For now, think of the factory method as "registering a service" in the module. The factory method is not providing a factory for the module itself, as the name might imply. 

Yet another hunk of script from a different file can add a logger service to the same module.

(function() {

    var logger = function() {
      
        var log = function(message) {
            // .. do something loggy
        };

        return {
            log: log,            
        };
    };

    angular.module("patientApp.Services")
           .factory("logger", logger);           

}());

Of course, that could have all been combined together, if you so desire:

(function() {
    "use strict";

    var alerter = function () {
        //...
    };

    var logger = function() {
        //...
    };

    angular.module("patientApp.Services")
           .factory("alerter", alerter)
           .factory("logger", logger);           

}());

Now that we understand a bit about how to create modules, we'll talk about the "when and why" in a future post.