Al R.
Al R.

Reputation: 2480

How can you ensure that angular module dependencies get resolved?

Angular's documentation on modules (http://docs-angularjs-org-dev.appspot.com/guide/module) says:

Dependencies

Modules can list other modules as their dependencies. Depending on a module implies that required module needs to be loaded before the requiring module is loaded. In other words the configuration blocks of the required modules execute before the configuration blocks or the requiring module. The same is true for the run blocks. Each module can only be loaded once, even if multiple other modules require it.

I created this example (http://jsbin.com/IRogUxA/34/edit) which creates a controller module that depends on two "mid-level" modules, each of which depend on two "low-level" modules. So, I have two "mid-level" modules and four "low-level" modules.

Clearly, order does not matter in the JS source. In the example above I've defined the high level modules before the low level ones they reference. I understand that Angular makes use of dependency injection to wire up the dependencies, but the way it does so is mysterious to me.

My question: How does one ensure that the config blocks of the various modules are run in the proper order? Or more broadly, how is it that Angular can resolve all of my dependencies when they are defined in any order I choose (within the JS source code)?

Upvotes: 2

Views: 2249

Answers (2)

TJWorks
TJWorks

Reputation: 266

All the angular module API methods, such as "config", "factory" etc, are wrapped in a "invokeLater" function. In another word, when the dependency module is evaluated, the module.config, module.factory etc are not really called at that time. Instead those invocations are simply pushed into a queue.

Consider this example:

    var demo = angular.module('demo', ['module1']);
demo.config( function( ) {
            console.log("In app.config")
} ).run(function(){
    console.log("Angular run");
});

angular.module("module1", []).factory('myservice', function(){
    return {};
}).controller('mycontroller', function(){} );

For each module it has its own queue: (for the main module "demo")

var invokeQueue = [];
invokeQueue.push("demo.config", xxx);
invokeQueue.push("demo.run", xxx);

For module1:

var invokeQueue = [];
invokeQueue.push("module.factory", xxx);
invokeQueue.push("module.controller", xxx);

Once all the scripts are loaded and DOMContentLoaded event is fired , angular starts actually load/eval all the modules. At this time angular already constructed a full module dependency tree. The dependency module is always loaded first before the main module so in this case module1 will be loaded first and it's invokeQueue is called in the original order(module.factory, module.controller etc). Then back to the main module demo's invokeQueue, demo.config, demo.run

Upvotes: 2

SonOfNun
SonOfNun

Reputation: 957

I think it helps to think of modules as their own applications, not relying on ordering of other (external) dependencies. If order is important, then you can introduce a module that simply composes other modules and coordinates their interactions.

We avoid taking hard module references in our angular.module({moduleName},[deps]) calls, preferring to have those rolled up by a higher level module. That makes testing in isolation lots easier and you can stub out the services you rely on with lighter weight.

Upvotes: 1

Related Questions