Skip to content

Commit f098a44

Browse files
committed
fix(injector): invoke config blocks for module after all providers
This change ensures that a module's config blocks are always invoked after all of its providers are registered. BREAKING CHANGE: Previously, config blocks would be able to control behaviour of provider registration, due to being invoked prior to provider registration. Now, provider registration always occurs prior to configuration for a given module, and therefore config blocks are not able to have any control over a providers registration. Example: Previously, the following: angular.module('foo', []) .provider('$rootProvider', function() { this.$get = function() { ... } }) .config(function($rootProvider) { $rootProvider.dependentMode = "B"; }) .provider('$dependentProvider', function($rootProvider) { if ($rootProvider.dependentMode === "A") { this.$get = function() { // Special mode! } } else { this.$get = function() { // something else } } }); would have "worked", meaning behaviour of the config block between the registration of "$rootProvider" and "$dependentProvider" would have actually accomplished something and changed the behaviour of the app. This is no longer possible within a single module. Fixes angular#7139
1 parent d5a2069 commit f098a44

File tree

4 files changed

+47
-12
lines changed

4 files changed

+47
-12
lines changed

src/auto/injector.js

+13-8
Original file line numberDiff line numberDiff line change
@@ -693,22 +693,27 @@ function createInjector(modulesToLoad, strictDi) {
693693
// Module Loading
694694
////////////////////////////////////
695695
function loadModules(modulesToLoad){
696-
var runBlocks = [], moduleFn, invokeQueue, i, ii;
696+
var runBlocks = [], moduleFn, invokeQueue;
697697
forEach(modulesToLoad, function(module) {
698698
if (loadedModules.get(module)) return;
699699
loadedModules.put(module, true);
700700

701+
function runInvokeQueue(queue) {
702+
var i, ii;
703+
for(i = 0, ii = queue.length; i < ii; i++) {
704+
var invokeArgs = queue[i],
705+
provider = providerInjector.get(invokeArgs[0]);
706+
707+
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
708+
}
709+
}
710+
701711
try {
702712
if (isString(module)) {
703713
moduleFn = angularModule(module);
704714
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
705-
706-
for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
707-
var invokeArgs = invokeQueue[i],
708-
provider = providerInjector.get(invokeArgs[0]);
709-
710-
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
711-
}
715+
runInvokeQueue(moduleFn._invokeQueue);
716+
runInvokeQueue(moduleFn._configBlocks);
712717
} else if (isFunction(module)) {
713718
runBlocks.push(providerInjector.invoke(module));
714719
} else if (isArray(module)) {

src/loader.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,19 @@ function setupModuleLoader(window) {
9999
/** @type {!Array.<Array.<*>>} */
100100
var invokeQueue = [];
101101

102+
/** @type {!Array.<Function>} */
103+
var configBlocks = [];
104+
102105
/** @type {!Array.<Function>} */
103106
var runBlocks = [];
104107

105-
var config = invokeLater('$injector', 'invoke');
108+
var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
106109

107110
/** @type {angular.Module} */
108111
var moduleInstance = {
109112
// Private state
110113
_invokeQueue: invokeQueue,
114+
_configBlocks: configBlocks,
111115
_runBlocks: runBlocks,
112116

113117
/**
@@ -297,9 +301,10 @@ function setupModuleLoader(window) {
297301
* @param {String=} insertMethod
298302
* @returns {angular.Module}
299303
*/
300-
function invokeLater(provider, method, insertMethod) {
304+
function invokeLater(provider, method, insertMethod, queue) {
305+
if (!queue) queue = invokeQueue;
301306
return function() {
302-
invokeQueue[insertMethod || 'push']([provider, method, arguments]);
307+
queue[insertMethod || 'push']([provider, method, arguments]);
303308
return moduleInstance;
304309
};
305310
}

test/auto/injectorSpec.js

+23
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,29 @@ describe('injector', function() {
305305
expect(log).toEqual('abABCD');
306306
});
307307

308+
it('should execute own config blocks after all own providers are invoked', function() {
309+
var log = '';
310+
angular.module('a', ['b'])
311+
.provider('$a', function() {
312+
log += '$aProvider;';
313+
this.$get = function() {};
314+
})
315+
.config(function($aProvider) {
316+
log += 'aConfig;';
317+
});
318+
angular.module('b', [])
319+
.provider('$b', function() {
320+
log += '$bProvider;';
321+
this.$get = function() {};
322+
})
323+
.config(function($bProvider) {
324+
log += 'bConfig;';
325+
});
326+
327+
createInjector(['a']);
328+
expect(log).toBe('$bProvider;bConfig;$aProvider;aConfig;');
329+
});
330+
308331
describe('$provide', function() {
309332

310333
it('should throw an exception if we try to register a service called "hasOwnProperty"', function() {

test/loaderSpec.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,16 @@ describe('module loader', function() {
4646
expect(myModule.requires).toEqual(['other']);
4747
expect(myModule._invokeQueue).toEqual([
4848
['$provide', 'constant', ['abc', 123] ],
49-
['$injector', 'invoke', ['config'] ],
5049
['$provide', 'provider', ['sk', 'sv'] ],
5150
['$provide', 'factory', ['fk', 'fv'] ],
5251
['$provide', 'service', ['a', 'aa'] ],
5352
['$provide', 'value', ['k', 'v'] ],
5453
['$filterProvider', 'register', ['f', 'ff'] ],
5554
['$compileProvider', 'directive', ['d', 'dd'] ],
5655
['$controllerProvider', 'register', ['ctrl', 'ccc']],
56+
]);
57+
expect(myModule._configBlocks).toEqual([
58+
['$injector', 'invoke', ['config'] ],
5759
['$injector', 'invoke', ['init2'] ]
5860
]);
5961
expect(myModule._runBlocks).toEqual(['runBlock']);

0 commit comments

Comments
 (0)