Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit c0b4e2d

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 #7139 Closes #7147
1 parent 924ee6d commit c0b4e2d

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
/**
@@ -299,9 +303,10 @@ function setupModuleLoader(window) {
299303
* @param {String=} insertMethod
300304
* @returns {angular.Module}
301305
*/
302-
function invokeLater(provider, method, insertMethod) {
306+
function invokeLater(provider, method, insertMethod, queue) {
307+
if (!queue) queue = invokeQueue;
303308
return function() {
304-
invokeQueue[insertMethod || 'push']([provider, method, arguments]);
309+
queue[insertMethod || 'push']([provider, method, arguments]);
305310
return moduleInstance;
306311
};
307312
}

test/auto/injectorSpec.js

+23
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,29 @@ describe('injector', function() {
308308
expect(log).toEqual('abABCD');
309309
});
310310

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

313336
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)