首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何通过变量调用ng-template?

如何通过变量调用ng-template?
EN

Stack Overflow用户
提问于 2019-06-21 10:51:41
回答 3查看 884关注 0票数 1

我查过了:ViewChildren for ng-templateAccess multiple viewchildren using @viewchild

但是我不能通过变量的值来调用我的模板...

所以我的模板是这样的:

代码语言:javascript
复制
<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

代码语言:javascript
复制
export class SomeClass {
   @ViewChildren(TemplateRef) templates: QueryList<TemplateRef<any>>;
}

所以我的想法是,我认为我应该能够通过执行templates[feature]引用正确的模板,这应该会产生类似templates['myFeature']的东西,并给我正确的模板……但事实并非如此。

我如何将其存档?

EN

回答 3

Stack Overflow用户

发布于 2019-06-21 11:22:50

由于您已经创建了不同的模板(不同的模板变量),因此您需要为每个模板创建不同的视图子视图。只有当它们具有相同的模板引用变量时,ViewChildren才会起作用。在您的代码中的用法它将获取每个模板实例,因为您传递的是TemplateRef,它将获取此类型的每个实例。

我已经创建了一个stackblitz,它演示了this

还要注意,您的模板实例将仅在ngAfterViewInit()上可用,在此之前它将是未定义的。

票数 1
EN

Stack Overflow用户

发布于 2019-06-21 20:57:33

ngAfterViewInit内部进行了一些修补之后,我让它按照我想要的方式工作。有点难看,因为我需要使用setTimeout,我需要使用内部变量(不确定这是不是一个好主意)……

这是一个stackblitz,展示了动态模板选择和渲染的变量值。

简而言之,以下是我是如何做到的,你需要3件事情:

代码语言:javascript
复制
// 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

代码语言:javascript
复制
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;
  });
}
票数 0
EN

Stack Overflow用户

发布于 2020-04-15 18:43:39

解释

ViewChildren指令的值将存储在ngAfterViewInit() (see this)之前。

Angular首先检查你的模板,发现templatesundefined

然后,它开始呈现视图。在这个过程中,它解析像ViewChildren()这样的模板指令并调用ngAfterViewInit()

在这个过程中,templates被设置,这意味着视图现在处于不一致的状态。

页面的初始呈现会导致页面本身的更改

这时你就会得到臭名昭著的“表情已经改变...”错误。

解决方案

您不能更改何时设置templates,因为它是由Angular编排的。

不过,所能做的就是为绑定使用另一个变量,并在初始视图呈现完成后将其设置为templates

尝试在ngAfterViewInit()中设置新变量将再次触发“表达式已更改”错误,因为此生命周期挂钩本身是初始呈现的一部分。

解决方案是将ngAfterViewInit()中新变量的设置推迟到下一轮VM。

要做到这一点,我们可以简单地使用不带第二个参数的setTimeout()

代码语言:javascript
复制
export class AppComponent implements AfterViewInit {
  @ViewChildren(TemplateRef) templates!: QueryList<TemplateRef<any>>;
  features: TemplateRef<any>[] = [];
  name = "Angular";

  ngAfterViewInit() {
    setTimeout(() => this.features = this.templates.toArray());
  }
}

查看此stackblitz example

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56696255

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档