feat: allow direct scoping of @Injectables to the root injector (#22185)

@Injectable() supports a scope parameter which specifies the target module.
However, it's still difficult to specify that a particular service belongs
in the root injector. A developer attempting to ensure that must either
also provide a module intended for placement in the root injector or target
a module known to already be in the root injector (e.g. BrowserModule).
Both of these strategies are cumbersome and brittle.

Instead, this commit adds a token APP_ROOT_SCOPE which provides a
straightforward way of targeting the root injector directly, without
requiring special knowledge of modules within it.

PR Close #22185
This commit is contained in:
Alex Rickabaugh
2018-02-12 15:23:46 -08:00
committed by Victor Berchet
parent 029dbf0e18
commit 7ac34e42a0
12 changed files with 152 additions and 3 deletions

View File

@ -8,6 +8,7 @@
import {resolveForwardRef} from '../di/forward_ref';
import {InjectFlags, Injector, setCurrentInjector} from '../di/injector';
import {APP_ROOT_SCOPE} from '../di/scope';
import {NgModuleRef} from '../linker/ng_module_factory';
import {stringify} from '../util';
@ -43,8 +44,12 @@ export function moduleProvideDef(
export function moduleDef(providers: NgModuleProviderDef[]): NgModuleDefinition {
const providersByKey: {[key: string]: NgModuleProviderDef} = {};
const modules = [];
let isRoot: boolean = false;
for (let i = 0; i < providers.length; i++) {
const provider = providers[i];
if (provider.token === APP_ROOT_SCOPE) {
isRoot = true;
}
if (provider.flags & NodeFlags.TypeNgModule) {
modules.push(provider.token);
}
@ -57,6 +62,7 @@ export function moduleDef(providers: NgModuleProviderDef[]): NgModuleDefinition
providersByKey,
providers,
modules,
isRoot,
};
}
@ -119,8 +125,13 @@ export function resolveNgModuleDep(
return data._parent.get(depDef.token, notFoundValue);
}
function moduleTransitivelyPresent(ngModule: NgModuleData, scope: any): boolean {
return ngModule._def.modules.indexOf(scope) > -1;
}
function targetsModule(ngModule: NgModuleData, def: InjectableDef): boolean {
return def.scope != null && ngModule._def.modules.indexOf(def.scope) > -1;
return def.scope != null && (moduleTransitivelyPresent(ngModule, def.scope) ||
def.scope === APP_ROOT_SCOPE && ngModule._def.isRoot);
}
function _createProviderInstance(ngModule: NgModuleData, providerDef: NgModuleProviderDef): any {

View File

@ -43,6 +43,7 @@ export interface NgModuleDefinition extends Definition<NgModuleDefinitionFactory
providers: NgModuleProviderDef[];
providersByKey: {[tokenKey: string]: NgModuleProviderDef};
modules: any[];
isRoot: boolean;
}
export interface NgModuleDefinitionFactory extends DefinitionFactory<NgModuleDefinition> {}