поэтому самая прагматичная c вещь здесь заключается в том, чтобы просто поместить дочернего элемента, которого вы хотите передать в качестве дочернего элемента компонента template-lookup
, и использовать ng-content
...
сделать это в родитель:
<template-lookup>
<div>I will pass to child</div>
</template-lookup>
<div class="NA-TEMPLATE-CHOOSER" *replaceWith="'flexCol'">
</div>
и это у ребенка:
<ng-template #flexRow></ng-template>
<ng-template #flexCol>
<xfr-flex-col>
<ng-content></ng-content>
</xfr-flex-col>
</ng-template>
, и это решит вашу проблему / выполнит заявленные требования.
Вы также можете рассмотреть возможность переписывания в вашем сервисе для решения проблем синхронизации между шаблонами, которые устанавливаются и получают раз и навсегда:
import { Injectable, TemplateRef } from "@angular/core";
import {ReplaySubject} from 'rxjs';
import {map, filter, distinctUntilChanged} from 'rxjs/operators';
@Injectable({providedIn: 'root'}) // provide appropriately, root for example
export class TemplateStore {
private templates = new Map<string, TemplateRef<any>>();
private tmpSource = new ReplaySubject<Map<string, TemplateRef<any>>>(1);
setTemplate(key: string, template: TemplateRef<any>) {
this.templates.set(key, template);
this.tmpSource.next(this.templates)
}
getTemplate(key: string) {
return this.tmpSource.pipe(
map(tmpMap => tmpMap.get(key)),
filter(tmp => !!tmp),
distinctUntilChanged()
)
}
}
и вносить соответствующие изменения в директиву и дочерние компоненты. ...
export class CompositeTemplateDirective implements OnInit, OnDestroy {
@Input() replaceWith: "flex-col" | "flex-row";
private sub: Subscription;
constructor(private service: TemplateStore, private viewContainer: ViewContainerRef) { }
ngOnInit() {
this.sub = this.service.getTemplate(this.replaceWith).subscribe(t => {
this.viewContainer.clear()
this.viewContainer.createEmbeddedView(t)
})
}
ngOnDestroy() {
this.sub.unsubscribe()
}
}
export class TemplateLookup {
@ViewChild("flexRow") flexRowTemplate;
@ViewChild("flexCol") flexColTemplate;
constructor(private service: TemplateStore) {}
ngAfterViewInit() {
this.service.setTemplate("flexRow", this.flexRowTemplate);
this.service.setTemplate("flexCol", this.flexColTemplate);
}
}
пример работы: https://stackblitz.com/edit/angular-ygdveu
было отмечено, что это не поддерживает вложение ... поэтому выполните следующие настройки и ты можешь вкладывать в поиске по шаблону вам нужно будет использовать модификатор SkipSelf
в своем конструкторе, а также предоставить TemplateStore ... в случае отсутствия вложений это не даст никакого эффекта, SkipSelf
просто скажет инжектору начать поиск для службы у родителя, а не в компоненте:
@Component({
selector: "template-lookup",
template: `
<ng-template #flexRow>FLEX ROW</ng-template>
<ng-template #flexCol>
FLEX COL
<div class="flex-col">
<ng-content></ng-content>
</div>
</ng-template>
`,
providers: [TemplateStore]
})
export class TemplateLookup {
@ViewChild("flexRow") flexRowTemplate;
@ViewChild("flexCol") flexColTemplate;
constructor(@SkipSelf() private service: TemplateStore) {}
ngAfterViewInit() {
this.service.setTemplate("flexRow", this.flexRowTemplate);
this.service.setTemplate("flexCol", this.flexColTemplate);
}
}
, тогда вы можете вкладывать в свои сердца содержимое так:
<template-lookup>
<div>I can pass this to the child!</div>
<template-lookup>NESTED</template-lookup>
<div class="nested-content" *replaceWith="'flexCol'"></div>
</template-lookup>
<div class="NA-TEMPLATE-CHOOSER" *replaceWith="'flexCol'">
</div>
, что немного уродливо, так как вам нужно повторить компонент поиска шаблона, но он выполняет свою работу. Это работает, позволяя директиве и поиску шаблона взаимодействовать с другой копией TemplateStore, чтобы вы могли вкладывать другое содержимое.
рабочий пример этого варианта: https://stackblitz.com/edit/angular-lpner2