我检查了: ViewChildren for ng-template 和 Access multiple viewchildren using @viewchild
但是我无法通过变量的值来调用我的模板...
所以我的模板是这样的:
<ng-container *ngFor="let feature of Object.values(features)">
<ng-container *ngTemplateOutlet="templates[feature]"></ng-container>
</ng-container>
<ng-template #myFeature>
Nothing to see here
</ng-template>
<ng-template #myOtherFeature>
Nothing to see here
</ng-template>
features
是一个枚举,其值与模板名称匹配...然后在我的课堂上,我试图像这样抓住所有ViewChildren
:
export class SomeClass {
@ViewChildren(TemplateRef) templates: QueryList<TemplateRef<any>>;
}
因此,我的想法是,我认为我应该能够通过执行templates[feature]
来引用正确的模板,该模板应产生类似templates['myFeature']
的内容,并为我提供正确的模板...但是不是。
如何存档?
答案 0 :(得分:0)
由于创建了不同的模板(不同的模板变量),因此需要为每个模板创建不同的视图子级。 ViewChildren仅在它们具有相同的模板引用变量的情况下才能工作。而且您代码中的用法将获取每个模板实例,因为您正在传递TemplateRef
,它将获取此类型的每个实例。
我创建了一个堆叠闪电战,展示了this。
另外请注意,您的模板实例将仅在ngAfterViewInit()
上可用,直到那时它才是未定义的。
答案 1 :(得分:0)
在ngAfterViewInit
内进行了一些修补之后,我开始按照自己的方式工作。有点丑陋,因为我需要使用setTimeout
并且需要使用内部变量(不确定这是否是个好主意)...
这是stackblitz展示柜动态模板的选择和按可变值的呈现。
简而言之,这是我的工作方式,您需要做三件事:
// to grab all the templates
@ViewChildren(TemplateRef) templates: QueryList<TemplateRef<any>>;
// to be use for template selection
templateMap: { [key: string]: TemplateRef<any> } = {};
// to avoid rendering during the first run when templateMap is not yet ready
templateMapReady = false;
然后在ngAfterViewInit
中执行以下操作以构建templateMap
:
ngAfterViewInit(): void {
// setTimeout to bypass the ExpressionChangedAfterItHasBeenCheckedError
setTimeout(() => {
// loop through the fetched template
this.templates.toArray().forEach(t => {
// for those ng-template that has a #name, they will have references
const keys = Object.keys((t as any)._def.references);
if (keys.length === 1) {
// so we put these in the templateMap
this.templateMap[keys[0]] = t;
}
});
// now we change it to ready, so it would render it
this.templateMapReady = true;
});
}
答案 2 :(得分:0)
ViewChildren 指令的值将存储在 ngAfterViewInit()(see this)之前。
Angular首先检查您的模板,发现templates
为undefined
。
然后开始渲染视图。在此过程中,它将解析ViewChildren()
之类的Template指令并调用ngAfterViewInit()
。
在此过程中,templates
被设置,这意味着视图现在处于不一致状态。
页面的初始呈现导致页面本身的更改 。
那是当您收到臭名昭著的“表达式已更改...” 错误。
设置为templates
时不能更改,这是由Angular精心安排的。
您可以进行的操作是,使用另一个变量进行绑定,并在完成初始视图渲染后将其设置为templates
。
尝试在ngAfterViewInit()
中设置新变量将再次触发“表达式已更改”错误,因为此生命周期挂钩本身是初始呈现的一部分。
解决方案是将ngAfterViewInit()
中新变量的设置推迟到下一个VM轮换。
为此,我们可以简单地使用setTimeout()
而不使用第二个参数:
export class AppComponent implements AfterViewInit {
@ViewChildren(TemplateRef) templates!: QueryList<TemplateRef<any>>;
features: TemplateRef<any>[] = [];
name = "Angular";
ngAfterViewInit() {
setTimeout(() => this.features = this.templates.toArray());
}
}