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._preBuiltObjects = preBuiltObjects;
|
||||
|
||||
this._reattachInjectors(imperativelyCreatedInjector, host);
|
||||
this._reattachInjectors(imperativelyCreatedInjector);
|
||||
this._strategy.hydrate();
|
||||
|
||||
if (isPresent(host)) {
|
||||
|
@ -489,52 +489,37 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
|
|||
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)) {
|
||||
this._reattachInjector(this._injector, this._parent._injector, false);
|
||||
} else {
|
||||
// This injector is at the boundary.
|
||||
//
|
||||
// The injector tree we are assembling:
|
||||
//
|
||||
// host._injector (only if present)
|
||||
// |
|
||||
// |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);
|
||||
if (isPresent(imperativelyCreatedInjector)) {
|
||||
// The imperative injector is similar to having an element between
|
||||
// the dynamic-loaded component and its parent => no boundaries.
|
||||
this._reattachInjector(this._injector, imperativelyCreatedInjector, false);
|
||||
this._reattachInjector(imperativelyCreatedInjector, this._parent._injector, false);
|
||||
} else {
|
||||
this._reattachInjector(this._injector, this._parent._injector, false);
|
||||
}
|
||||
|
||||
// host._injector OR imperativelyCreatedInjector OR null
|
||||
// |
|
||||
// |boundary
|
||||
// |
|
||||
// this._injector
|
||||
var parent = this._closestBoundaryInjector(imperativelyCreatedInjector, host);
|
||||
this._reattachInjector(this._injector, parent, true);
|
||||
}
|
||||
}
|
||||
// Dynamically-loaded component in the template. A root ElementInjector.
|
||||
} else if (isPresent(this._host)) {
|
||||
// The imperative injector is similar to having an element between
|
||||
// the dynamic-loaded component and its parent => no boundary between
|
||||
// the component and imperativelyCreatedInjector.
|
||||
// But since it is a root ElementInjector, we need to create a boundary
|
||||
// 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,
|
||||
host: ElementInjector): Injector {
|
||||
if (isPresent(imperativelyCreatedInjector)) {
|
||||
return imperativelyCreatedInjector;
|
||||
} else if (isPresent(host)) {
|
||||
return host._injector;
|
||||
// Bootstrap
|
||||
} else {
|
||||
return null;
|
||||
if (isPresent(imperativelyCreatedInjector)) {
|
||||
this._reattachInjector(this._injector, imperativelyCreatedInjector, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -247,7 +247,7 @@ export function main() {
|
|||
|
||||
for (var i = 0; i < 20; i++) {
|
||||
dynamicBindings.push(bind(i).toValue(i));
|
||||
}
|
||||
}
|
||||
|
||||
function createPei(parent, index, bindings, distance = 1, hasShadowRoot = false, dirVariableBindings = null) {
|
||||
var directiveBinding = ListWrapper.map(bindings, b => {
|
||||
|
@ -278,7 +278,7 @@ export function main() {
|
|||
return inj;
|
||||
}
|
||||
|
||||
function parentChildInjectors(parentBindings, childBindings, parentPreBuildObjects = null) {
|
||||
function parentChildInjectors(parentBindings, childBindings, parentPreBuildObjects = null, imperativelyCreatedInjector = null) {
|
||||
if (isBlank(parentPreBuildObjects)) parentPreBuildObjects = defaultPreBuiltObjects;
|
||||
|
||||
var protoParent = createPei(null, 0, parentBindings);
|
||||
|
@ -288,20 +288,20 @@ export function main() {
|
|||
|
||||
var protoChild = createPei(protoParent, 1, childBindings, 1, false);
|
||||
var child = protoChild.instantiate(parent);
|
||||
child.hydrate(null, null, defaultPreBuiltObjects);
|
||||
child.hydrate(imperativelyCreatedInjector, null, defaultPreBuiltObjects);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
function hostShadowInjectors(hostBindings: List<any>,
|
||||
shadowBindings: List<any>): ElementInjector {
|
||||
shadowBindings: List<any>, imperativelyCreatedInjector = null): ElementInjector {
|
||||
var protoHost = createPei(null, 0, hostBindings, 0, true);
|
||||
var host = protoHost.instantiate(null);
|
||||
host.hydrate(null, null, defaultPreBuiltObjects);
|
||||
|
||||
var protoShadow = createPei(null, 0, shadowBindings, 0, false);
|
||||
var shadow = protoShadow.instantiate(null);
|
||||
shadow.hydrate(null, host, null);
|
||||
shadow.hydrate(imperativelyCreatedInjector, host, null);
|
||||
|
||||
return shadow;
|
||||
}
|
||||
|
@ -715,12 +715,32 @@ export function main() {
|
|||
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([
|
||||
bind("service").toValue('appService')
|
||||
]);
|
||||
var inj = injector([NeedsService], imperativelyCreatedInjector);
|
||||
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", () => {
|
||||
|
@ -1192,7 +1212,7 @@ export function main() {
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class ContextWithHandler {
|
||||
|
|
Loading…
Reference in New Issue