【问题标题】:How to render templates dynamically in Angular 2?如何在 Angular 2 中动态渲染模板?
【发布时间】:2017-03-12 14:09:53
【问题描述】:

我试图在视图中动态选择模板,只需使用 Angular 2 的传统“#”字符引用它们。 在我的项目中,我处理错误并将它们显示给用户,我有一个对话框组件,它的内容应该基于 html 动态注入,这就是我使用模板的原因。

我阅读了一些文章,其中展示了当我已经知道模板引用的名称时如何做到这一点的方法,在我的情况下,我不知道引用的名称,我在运行时获得了名称。 我特别遵循了本指南:https://www.bennadel.com/blog/3101-experimenting-with-dynamic-template-rendering-in-angular-2-rc-1.htm

所以目前我的对话框组件有以下视图:

<template #err_1 let-property1="p1" let-property2="p2">
property1: {{p1}}
property2: {{p2}}

</template>

<template #err_2 let-property1="p1" let-property2="p2">
<p *ngIf="p1">{{p1}}</p>
property2: {{p2}}
</template>

<!--The code for the template directive i took from the guide in the link above-->
<tem [render]="templateRef"
     [context]="context">
</tem>

在我的 dialog.ts 中,我有以下代码:

@Component({
  selector: 'error-dialog',
  queries: {
    templateRef: new ViewChild("err_1")
  },
  templateUrl: './dialog.html'
})
...

“TemplateRendererDirective”指令源是我从上面链接的指南中获取的。 请注意让我感到困惑的地方:即使指令最终获得 TemplateRef 实例,templateRef 基本上也会获得一个对象:“ViewChild”,这怎么可能?

所以只有当我知道我要渲染哪个错误模板时,例如:“err_1”我只是在 dialog.ts 中预先引用它,但事实并非如此,我想动态告诉我要渲染“err_1”,“ err_2" 等。并给出上下文(这是用数据填充该模板的对象 - 例如 p1、p2,也是动态的)

有可能吗?

【问题讨论】:

  • 你到底想要什么?更改templateRef 参数?
  • 动态设置 templateRef 参数,而不是像我在帖子中显示的那样声明对话框组件时。但是如何从 ViewChild 对象创建 TemplateRef?我需要 templateRef 对象,因为将内容注入视图的函数 createEmbededView 期望获得 templateRef
  • ViewChild 如果您的 err_1 哈希与 &lt;template&gt; 相关,则自动抓取 TemplateRef
  • 它与模板元素有关,那么如何从 ViewChild 获取 templateRef 对象?当我尝试简单地转换打字稿编译器时会出现错误
  • 添加请编码它的外观

标签: javascript angular


【解决方案1】:

正如我在 cmets 中提到的,您可以尝试使用 @ViewChildren 来完成它。但我使用附加指令TemplateNameDirective 来操作模板的name

它的外观如下:

@Directive({
  'selector': 'template[name]'
})
export class TemplateNameDirective {
  @Input() name: string;
  constructor(public templateRef: TemplateRef<any>) {}
}

@Component({
  selector: 'error-dialog',
  template: `
    <template name="err_1" let-item>
      property1: {{item.p1}}
      property2: {{item.p2}}
    </template>

    <template name="err_2" let-item>
      <p *ngIf="item.p1">{{item.p1}}</p>
      property2: {{item.p2}}
    </template>

    <!-- 
       I use ngTemplateOutlet directive 
       https://angular.io/docs/ts/latest/api/common/index/NgTemplateOutlet-directive.html 
    -->
    <template [ngTemplateOutlet]="templateRef" [ngOutletContext]="{ $implicit: context }">
    </template>
  `
})
export class ErrorDialogComponent {
  @ViewChildren(TemplateNameDirective) children: QueryList<TemplateNameDirective>;

  templateRef: TemplateRef<any>;
  context: any;

  public setContent(errTemplateName, context) {
    this.templateRef = this.children.toArray()
      .find(x => x.name === errTemplateName).templateRef; 
    this.context = context;
  }
}

父视图:

<error-dialog #dialogRef></error-dialog>
<button (click)="dialogRef.setContent('err_1', { p1: 'test'})">Test err_1</button>
<button (click)="dialogRef.setContent('err_2', { p2: 'test2'})">Test err_2</button>

Plunker Example

注意:我正在传递 ngOutletContext 类似具有 $implicit 属性的对象。

在上下文对象中使用键 $implicit 会将其值设置为 默认。

它的工作原理如下:

[ngOutletContext]="{ $implicit: row }"  ==> <template let-row>

[ngOutletContext]="{ item: row }"       ==> <template let-row="item">

【讨论】:

  • 不幸的是它不起作用,this.children 由于某种原因未定义,我将“name”属性放在模板元素中,但它对我不起作用。
  • 您必须将TemplateNameDirective 添加到'@NgModule` 的declarations 数组
  • 你能在 plunker 上重现它吗?
  • 您的示例作为一个独立的组件工作,但我使用 Material 2 对话框组件,如指南所示:github.com/angular/material2/tree/master/src/lib/dialog 如您所见,我打开对话框并将组件的名称作为当我这样做时,子属性由于某种原因仍未定义。
  • 你能改进这个 plunker plnkr.co/edit/6o8UrUwfLIEHBUa3IaBB?p=preview 来重现你的问题吗?
猜你喜欢
  • 2017-09-11
  • 1970-01-01
  • 2020-05-12
  • 2020-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多