Angular 4:带插值的动态模板

Posted

技术标签:

【中文标题】Angular 4:带插值的动态模板【英文标题】:Angular 4: Dynamic template with interpolation 【发布时间】:2017-12-20 03:07:45 【问题描述】:

我正在构建一个数据表组件,该组件被设计为非常通用的组件。

这个想法是这样定义表:

<app-datatable [items]="currentPageResult">
    <app-datatable-column attribute="id"
                          header="ID"></app-datatable-column>
    <app-datatable-column attribute="name"
                          header="First Name"></app-datatable-column>
    <app-datatable-column attribute="last_name"
                          header="Last Name"></app-datatable-column>
</app-datatable>

这样,我们可以将数组指定到datatable组件中,通过定义datatable-columns我们可以决定哪些属性应该显示表格。在内部,表格将按列执行 ngFor,按项目执行另一个 ngFor。

这部分很简单,现在工作得很好,当我想要自定义 html 内容到 td 时,事情变得很棘手;像这样的:

<app-datatable [items]="currentPageResult">
    <app-datatable-column attribute="id"
                          header="ID"
                          [template]="titleTemplate">
        <ng-template #titleTemplate>
            <a role="button" [routerLink]="[data.id]">
                data.id
            </a>
        </ng-template>
    </app-datatable-column>
    <app-datatable-column attribute="name"
                          header="First Name"></app-datatable-column>
    <app-datatable-column attribute="last_name"
                          header="Last Name"></app-datatable-column>
</app-datatable>

请注意,我使用data 作为迭代变量,但它实际上不起作用,我只是在说明我想要做什么。

为了解决这个问题,我使用了一个 '$data' 作为简单字符串和一个自定义指令来将 '$data' 替换为相应的列/行值。

在数据表组件中,我在每个 tbody td 上使用 appDatatableContent 指令,传递 row 数据和 colum 设置(该指令仅适用于列设置具有模板的情况):

<table class="table">
  <thead>
    <tr>
      <th *ngFor="let col of columns" [ngClass]="getColumnHeaderClasses(col)" (click)="onReorder(col)">col.header</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let row of items.Items">
      <td *ngFor="let col of columns" appDatatableContent [column]="col" [row]="row">
        <ng-container *ngIf="!col.template; else col.template">
          row[col.attribute]
        </ng-container>
      </td>
    </tr>
  </tbody>
</table>

并且该指令基本上会查找内部包含“$data”的元素,并将“$sdata”替换为相应的列值,如下所示:

ngAfterViewInit() 
  if (!this.column.template) 
    return;
  
  const element: HTMLElement = this.element.nativeElement;
  const value = this.row[this.column.attribute];

  const children = element.getElementsByTagName('*');
  const length = children.length;

  for (let i = 0; i < length; i++) 
    const currentNode = children[i];
    if (!currentNode.children || !currentNode.children.length) 
      const originalHTML: string = currentNode.innerHTML;
      const fixedHTML = originalHTML.replace('$data', value);
      currentNode.innerHTML = fixedHTML;
    
  

另外,请注意每个单元格都有&lt;ng-container *ngIf="!col.template; else col.template"&gt;,因此如果绑定了任何模板,单元格内容将呈现该模板,但问题是如何将参数(特别是行对象)传递给模板以便模板可以使用带有该参数的插值。

查看工作人员:https://plnkr.co/edit/84jhiquT5q3OQaCxTa5i

但这似乎不是最好的方法,因为我只是在替换一个字符串值,因此我无法充分利用 o 角功率。

那么,¿我如何定义一个可以使用迭代变量来呈现自定义单元格内容的动态模板?

【问题讨论】:

【参考方案1】:

您可以使用内置指令NgTemplateOutlet 轻松解决您的问题,该指令允许您将上下文传递给EmbeddedView (ng-template)

先删除DatatableContentDirective

然后更改标记

data-table.component.html

<td *ngFor="let col of columns">
  <ng-container *ngIf="!col.template; else customTemplate">
     row[col.attribute]
  </ng-container>
  <ng-template #customTemplate 
     [ngTemplateOutlet]="col.template"
     [ngTemplateOutletContext]=" col: col, row: row ">
  </ng-template>
</td>

在父组件中使用

<ng-template #titleTemplate let-col="col" let-row="row">
  <a role="button" ...>
       <b>Custom</b> row[col.attribute]
  </a>
</ng-template>

Plunker Example

另请参阅有关模板变量let-name的更多信息

What is $implicit in angular 2?

【讨论】:

@ThomasFournet 请检查更新的 plunker next.plnkr.co/edit/kfDD5P3hi4wtiUYp

以上是关于Angular 4:带插值的动态模板的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Angular 中绑定多个插值模板?

带有动态模板或 templateUrl 的 Angular 2/4 组件

带角度插值的内联 CSS

可以使用 Angular 4 中的插值将值添加到内联样式

没有模板局部变量的Angular 4访问模板元素

Angular 5 - 动态组件模板加载