fix(di): fixed dynamic component loading of components created in child injector
This commit is contained in:
parent
19e4ee81b9
commit
57496926ca
|
@ -476,7 +476,7 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
|
||||||
this._host = host;
|
this._host = host;
|
||||||
this._preBuiltObjects = preBuiltObjects;
|
this._preBuiltObjects = preBuiltObjects;
|
||||||
|
|
||||||
this._reattachInjectors(imperativelyCreatedInjector, host);
|
this._reattachInjectors(imperativelyCreatedInjector);
|
||||||
this._strategy.hydrate();
|
this._strategy.hydrate();
|
||||||
|
|
||||||
if (isPresent(host)) {
|
if (isPresent(host)) {
|
||||||
|
@ -489,52 +489,37 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
|
||||||
this.hydrated = true;
|
this.hydrated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _reattachInjectors(imperativelyCreatedInjector: Injector, host: ElementInjector): void {
|
private _reattachInjectors(imperativelyCreatedInjector: Injector): void {
|
||||||
|
// Dynamically-loaded component in the template. Not a root ElementInjector.
|
||||||
if (isPresent(this._parent)) {
|
if (isPresent(this._parent)) {
|
||||||
this._reattachInjector(this._injector, this._parent._injector, false);
|
if (isPresent(imperativelyCreatedInjector)) {
|
||||||
} else {
|
// The imperative injector is similar to having an element between
|
||||||
// This injector is at the boundary.
|
// the dynamic-loaded component and its parent => no boundaries.
|
||||||
//
|
this._reattachInjector(this._injector, imperativelyCreatedInjector, false);
|
||||||
// The injector tree we are assembling:
|
this._reattachInjector(imperativelyCreatedInjector, this._parent._injector, false);
|
||||||
//
|
} else {
|
||||||
// host._injector (only if present)
|
this._reattachInjector(this._injector, this._parent._injector, false);
|
||||||
// |
|
|
||||||
// |boundary
|
|
||||||
// |
|
|
||||||
// imperativelyCreatedInjector (only if present)
|
|
||||||
// |
|
|
||||||
// |boundary
|
|
||||||
// |
|
|
||||||
// this._injector
|
|
||||||
//
|
|
||||||
|
|
||||||
// host._injector (only if present)
|
|
||||||
// |
|
|
||||||
// |boundary
|
|
||||||
// |
|
|
||||||
// imperativelyCreatedInjector (only if present)
|
|
||||||
if (isPresent(imperativelyCreatedInjector) && isPresent(host)) {
|
|
||||||
this._reattachInjector(imperativelyCreatedInjector, host._injector, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// host._injector OR imperativelyCreatedInjector OR null
|
// Dynamically-loaded component in the template. A root ElementInjector.
|
||||||
// |
|
} else if (isPresent(this._host)) {
|
||||||
// |boundary
|
// The imperative injector is similar to having an element between
|
||||||
// |
|
// the dynamic-loaded component and its parent => no boundary between
|
||||||
// this._injector
|
// the component and imperativelyCreatedInjector.
|
||||||
var parent = this._closestBoundaryInjector(imperativelyCreatedInjector, host);
|
// But since it is a root ElementInjector, we need to create a boundary
|
||||||
this._reattachInjector(this._injector, parent, true);
|
// between imperativelyCreatedInjector and _host.
|
||||||
}
|
if (isPresent(imperativelyCreatedInjector)) {
|
||||||
}
|
this._reattachInjector(this._injector, imperativelyCreatedInjector, false);
|
||||||
|
this._reattachInjector(imperativelyCreatedInjector, this._host._injector, true);
|
||||||
|
} else {
|
||||||
|
this._reattachInjector(this._injector, this._host._injector, true);
|
||||||
|
}
|
||||||
|
|
||||||
private _closestBoundaryInjector(imperativelyCreatedInjector: Injector,
|
// Bootstrap
|
||||||
host: ElementInjector): Injector {
|
|
||||||
if (isPresent(imperativelyCreatedInjector)) {
|
|
||||||
return imperativelyCreatedInjector;
|
|
||||||
} else if (isPresent(host)) {
|
|
||||||
return host._injector;
|
|
||||||
} else {
|
} else {
|
||||||
return null;
|
if (isPresent(imperativelyCreatedInjector)) {
|
||||||
|
this._reattachInjector(this._injector, imperativelyCreatedInjector, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -278,7 +278,7 @@ export function main() {
|
||||||
return inj;
|
return inj;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parentChildInjectors(parentBindings, childBindings, parentPreBuildObjects = null) {
|
function parentChildInjectors(parentBindings, childBindings, parentPreBuildObjects = null, imperativelyCreatedInjector = null) {
|
||||||
if (isBlank(parentPreBuildObjects)) parentPreBuildObjects = defaultPreBuiltObjects;
|
if (isBlank(parentPreBuildObjects)) parentPreBuildObjects = defaultPreBuiltObjects;
|
||||||
|
|
||||||
var protoParent = createPei(null, 0, parentBindings);
|
var protoParent = createPei(null, 0, parentBindings);
|
||||||
|
@ -288,20 +288,20 @@ export function main() {
|
||||||
|
|
||||||
var protoChild = createPei(protoParent, 1, childBindings, 1, false);
|
var protoChild = createPei(protoParent, 1, childBindings, 1, false);
|
||||||
var child = protoChild.instantiate(parent);
|
var child = protoChild.instantiate(parent);
|
||||||
child.hydrate(null, null, defaultPreBuiltObjects);
|
child.hydrate(imperativelyCreatedInjector, null, defaultPreBuiltObjects);
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hostShadowInjectors(hostBindings: List<any>,
|
function hostShadowInjectors(hostBindings: List<any>,
|
||||||
shadowBindings: List<any>): ElementInjector {
|
shadowBindings: List<any>, imperativelyCreatedInjector = null): ElementInjector {
|
||||||
var protoHost = createPei(null, 0, hostBindings, 0, true);
|
var protoHost = createPei(null, 0, hostBindings, 0, true);
|
||||||
var host = protoHost.instantiate(null);
|
var host = protoHost.instantiate(null);
|
||||||
host.hydrate(null, null, defaultPreBuiltObjects);
|
host.hydrate(null, null, defaultPreBuiltObjects);
|
||||||
|
|
||||||
var protoShadow = createPei(null, 0, shadowBindings, 0, false);
|
var protoShadow = createPei(null, 0, shadowBindings, 0, false);
|
||||||
var shadow = protoShadow.instantiate(null);
|
var shadow = protoShadow.instantiate(null);
|
||||||
shadow.hydrate(null, host, null);
|
shadow.hydrate(imperativelyCreatedInjector, host, null);
|
||||||
|
|
||||||
return shadow;
|
return shadow;
|
||||||
}
|
}
|
||||||
|
@ -715,12 +715,32 @@ export function main() {
|
||||||
expect(shadowInj.get(NeedsService).service).toEqual('hostService');
|
expect(shadowInj.get(NeedsService).service).toEqual('hostService');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should instantiate directives that depend on imperativley created injector bindings", () => {
|
it("should instantiate directives that depend on imperatively created injector bindings (bootstrap)", () => {
|
||||||
var imperativelyCreatedInjector = Injector.resolveAndCreate([
|
var imperativelyCreatedInjector = Injector.resolveAndCreate([
|
||||||
bind("service").toValue('appService')
|
bind("service").toValue('appService')
|
||||||
]);
|
]);
|
||||||
var inj = injector([NeedsService], imperativelyCreatedInjector);
|
var inj = injector([NeedsService], imperativelyCreatedInjector);
|
||||||
expect(inj.get(NeedsService).service).toEqual('appService');
|
expect(inj.get(NeedsService).service).toEqual('appService');
|
||||||
|
|
||||||
|
expect(() => injector([NeedsAncestorService], imperativelyCreatedInjector)).toThrowError();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should instantiate directives that depend on imperatively created injector bindings (root injector)", () => {
|
||||||
|
var imperativelyCreatedInjector = Injector.resolveAndCreate([
|
||||||
|
bind("service").toValue('appService')
|
||||||
|
]);
|
||||||
|
var inj = hostShadowInjectors([SimpleDirective], [NeedsService, NeedsAncestorService], imperativelyCreatedInjector);
|
||||||
|
expect(inj.get(NeedsService).service).toEqual('appService');
|
||||||
|
expect(inj.get(NeedsAncestorService).service).toEqual('appService');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should instantiate directives that depend on imperatively created injector bindings (child injector)", () => {
|
||||||
|
var imperativelyCreatedInjector = Injector.resolveAndCreate([
|
||||||
|
bind("service").toValue('appService')
|
||||||
|
]);
|
||||||
|
var inj = parentChildInjectors([], [NeedsService, NeedsAncestorService], null, imperativelyCreatedInjector);
|
||||||
|
expect(inj.get(NeedsService).service).toEqual('appService');
|
||||||
|
expect(inj.get(NeedsAncestorService).service).toEqual('appService');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should prioritize viewInjector over hostInjector for the same binding", () => {
|
it("should prioritize viewInjector over hostInjector for the same binding", () => {
|
||||||
|
|
Loading…
Reference in New Issue