fix(compiler): correctly instantiate eager providers that are used via Injector.get
(#19558)
Closes #15501 PR Close #19558
This commit is contained in:

committed by
Chuck Jazdzewski

parent
d30ce19231
commit
6ade68cff1
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user