fix(compiler): correctly instantiate eager providers that are used via Injector.get (#19558)

Closes #15501

PR Close #19558
This commit is contained in:
Tobias Bosch
2017-10-04 09:13:22 -07:00
committed by Chuck Jazdzewski
parent d30ce19231
commit 6ade68cff1
6 changed files with 163 additions and 24 deletions

View File

@ -13,7 +13,7 @@ import {NgModuleRef} from '../linker/ng_module_factory';
import {DepDef, DepFlags, NgModuleData, NgModuleDefinition, NgModuleProviderDef, NodeFlags} from './types';
import {splitDepsDsl, tokenKey} from './util';
const NOT_CREATED = new Object();
const UNDEFINED_VALUE = new Object();
const InjectorRefTokenKey = tokenKey(Injector);
const NgModuleRefTokenKey = tokenKey(NgModuleRef);
@ -53,8 +53,9 @@ export function initNgModule(data: NgModuleData) {
const providers = data._providers = new Array(def.providers.length);
for (let i = 0; i < def.providers.length; i++) {
const provDef = def.providers[i];
providers[i] = provDef.flags & NodeFlags.LazyProvider ? NOT_CREATED :
_createProviderInstance(data, provDef);
if (!(provDef.flags & NodeFlags.LazyProvider)) {
providers[i] = _createProviderInstance(data, provDef);
}
}
}
@ -78,27 +79,33 @@ export function resolveNgModuleDep(
const providerDef = data._def.providersByKey[tokenKey];
if (providerDef) {
let providerInstance = data._providers[providerDef.index];
if (providerInstance === NOT_CREATED) {
if (providerInstance === undefined) {
providerInstance = data._providers[providerDef.index] =
_createProviderInstance(data, providerDef);
}
return providerInstance;
return providerInstance === UNDEFINED_VALUE ? undefined : providerInstance;
}
return data._parent.get(depDef.token, notFoundValue);
}
function _createProviderInstance(ngModule: NgModuleData, providerDef: NgModuleProviderDef): any {
let injectable: any;
switch (providerDef.flags & NodeFlags.Types) {
case NodeFlags.TypeClassProvider:
return _createClass(ngModule, providerDef.value, providerDef.deps);
injectable = _createClass(ngModule, providerDef.value, providerDef.deps);
break;
case NodeFlags.TypeFactoryProvider:
return _callFactory(ngModule, providerDef.value, providerDef.deps);
injectable = _callFactory(ngModule, providerDef.value, providerDef.deps);
break;
case NodeFlags.TypeUseExistingProvider:
return resolveNgModuleDep(ngModule, providerDef.deps[0]);
injectable = resolveNgModuleDep(ngModule, providerDef.deps[0]);
break;
case NodeFlags.TypeValueProvider:
return providerDef.value;
injectable = providerDef.value;
break;
}
return injectable === undefined ? UNDEFINED_VALUE : injectable;
}
function _createClass(ngModule: NgModuleData, ctor: any, deps: DepDef[]): any {
@ -151,7 +158,7 @@ export function callNgModuleLifecycle(ngModule: NgModuleData, lifecycles: NodeFl
const provDef = def.providers[i];
if (provDef.flags & NodeFlags.OnDestroy) {
const instance = ngModule._providers[i];
if (instance && instance !== NOT_CREATED) {
if (instance && instance !== UNDEFINED_VALUE) {
instance.ngOnDestroy();
}
}

View File

@ -25,8 +25,6 @@ const TemplateRefTokenKey = tokenKey(TemplateRef);
const ChangeDetectorRefTokenKey = tokenKey(ChangeDetectorRef);
const InjectorRefTokenKey = tokenKey(Injector);
const NOT_CREATED = new Object();
export function directiveDef(
checkIndex: number, flags: NodeFlags,
matchedQueries: null | [string | number, QueryValueType][], childCount: number, ctor: any,
@ -111,7 +109,7 @@ export function _def(
}
export function createProviderInstance(view: ViewData, def: NodeDef): any {
return def.flags & NodeFlags.LazyProvider ? NOT_CREATED : _createProviderInstance(view, def);
return _createProviderInstance(view, def);
}
export function createPipeInstance(view: ViewData, def: NodeDef): any {
@ -378,9 +376,10 @@ export function resolveDep(
(allowPrivateServices ? elDef.element !.allProviders :
elDef.element !.publicProviders) ![tokenKey];
if (providerDef) {
const providerData = asProviderData(view, providerDef.nodeIndex);
if (providerData.instance === NOT_CREATED) {
providerData.instance = _createProviderInstance(view, providerDef);
let providerData = asProviderData(view, providerDef.nodeIndex);
if (!providerData) {
providerData = {instance: _createProviderInstance(view, providerDef)};
view.nodes[providerDef.nodeIndex] = providerData as any;
}
return providerData.instance;
}
@ -487,8 +486,12 @@ function callElementProvidersLifecycles(view: ViewData, elDef: NodeDef, lifecycl
}
function callProviderLifecycles(view: ViewData, index: number, lifecycles: NodeFlags) {
const provider = asProviderData(view, index).instance;
if (provider === NOT_CREATED) {
const providerData = asProviderData(view, index);
if (!providerData) {
return;
}
const provider = providerData.instance;
if (!provider) {
return;
}
Services.setCurrentNode(view, index);

View File

@ -284,8 +284,11 @@ function createViewNodes(view: ViewData) {
case NodeFlags.TypeFactoryProvider:
case NodeFlags.TypeUseExistingProvider:
case NodeFlags.TypeValueProvider: {
const instance = createProviderInstance(view, nodeDef);
nodeData = <ProviderData>{instance};
nodeData = nodes[i];
if (!nodeData && !(nodeDef.flags & NodeFlags.LazyProvider)) {
const instance = createProviderInstance(view, nodeDef);
nodeData = <ProviderData>{instance};
}
break;
}
case NodeFlags.TypePipe: {
@ -294,11 +297,14 @@ function createViewNodes(view: ViewData) {
break;
}
case NodeFlags.TypeDirective: {
const instance = createDirectiveInstance(view, nodeDef);
nodeData = <ProviderData>{instance};
nodeData = nodes[i];
if (!nodeData) {
const instance = createDirectiveInstance(view, nodeDef);
nodeData = <ProviderData>{instance};
}
if (nodeDef.flags & NodeFlags.Component) {
const compView = asElementData(view, nodeDef.parent !.nodeIndex).componentView;
initView(compView, instance, instance);
initView(compView, nodeData.instance, nodeData.instance);
}
break;
}