我查过了: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']的东西,并给我正确的模板……但事实并非如此。
我如何将其存档?
发布于 2019-06-21 11:22:50
由于您已经创建了不同的模板(不同的模板变量),因此您需要为每个模板创建不同的视图子视图。只有当它们具有相同的模板引用变量时,ViewChildren才会起作用。在您的代码中的用法它将获取每个模板实例,因为您传递的是TemplateRef,它将获取此类型的每个实例。
我已经创建了一个stackblitz,它演示了this。
还要注意,您的模板实例将仅在ngAfterViewInit()上可用,在此之前它将是未定义的。
发布于 2019-06-21 20:57:33
在ngAfterViewInit内部进行了一些修补之后,我让它按照我想要的方式工作。有点难看,因为我需要使用setTimeout,我需要使用内部变量(不确定这是不是一个好主意)……
这是一个stackblitz,展示了动态模板选择和渲染的变量值。
简而言之,以下是我是如何做到的,你需要3件事情:
// 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;
});
}发布于 2020-04-15 18:43:39
解释
ViewChildren指令的值将存储在ngAfterViewInit() (see this)之前。
Angular首先检查你的模板,发现templates为undefined。
然后,它开始呈现视图。在这个过程中,它解析像ViewChildren()这样的模板指令并调用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());
}
}https://stackoverflow.com/questions/56696255
复制相似问题