如何在Angular 2中动态地渲染模板?

3
我试图在视图中通过引用带有传统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 参数吗? - yurzui
ViewChild grabs TemplateRef automatically if your err_1 hash relates to <template> - yurzui
这与模板元素有关,那么我该如何从ViewChild中获取templateRef对象?当我尝试简单地进行类型转换时,TypeScript编译器会报错。 - Lihai
请添加代码,看起来是这样的。 - yurzui
如果您阅读了本文的评论,那么您就会知道有一个名为ngTemplateOutlet指令,它与TemplateRendererDirective执行相同的操作。https://www.bennadel.com/blog/3102-templates-appear-to-maintain-lexical-bindings-in-angular-2-rc-1.htm - yurzui
显示剩余4条评论
1个回答

5

如我在评论中提到的,你可以尝试使用@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示例

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

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

它的工作原理如下:

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

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

很遗憾它不起作用,由于某些原因,this.children未定义,我在模板元素中放置了“name”属性,但对我来说它不起作用。 - Lihai
你需要将 TemplateNameDirective 添加到 @NgModuledeclarations 数组中。 - yurzui
你的示例作为一个自主独立的组件可以工作,但是我正在使用Material 2对话框组件,就像这里的指南所示:https://github.com/angular/material2/tree/master/src/lib/dialog。正如你所看到的,当我打开对话框并将组件名称作为参数传递时,children属性因某种原因保持未定义状态。 - Lihai
你能否改进这个 plunker https://plnkr.co/edit/6o8UrUwfLIEHBUa3IaBB?p=preview 来重现你的问题呢? - yurzui
请看这里:https://embed.plnkr.co/4OJG4Id6FC0xk67q70iJ/ 出现的错误是:“Cannot read property 'toArray' of undefined”,出现在“setContent”函数中。 - Lihai
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接