Angular 4:带插值的动态模板
Angular 4: Dynamic template with interpolation
我正在构建一个数据 table 组件,该组件被设计为非常通用的组件。
想法是将 table 定义为:
<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,我们可以决定属性应该显示table.在内部 table 将按列执行 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”作为一个简单的字符串和一个自定义指令来用相应的 column/row 值替换“$data”。
在数据table 组件中,我在每个 tbody td
passig row
数据和 colum
设置上使用 appDatatableContent
指令(指令仅适用于列设置有模板的情况):
<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;
}
}
}
此外,请注意每个单元格都有 <ng-container *ngIf="!col.template; else col.template">
,因此如果绑定了任何模板,单元格内容将呈现该模板,但问题是如何将参数(特别是行对象)传递给模板因此模板可以使用带有该参数的插值。
查看正在工作的 plunker:https://plnkr.co/edit/84jhiquT5q3OQaCxTa5i
但这似乎不是最好的方法,因为我无法充分利用 angular 的强大功能,因为我只是替换字符串值。
那么,¿如何定义一个动态模板,它可以使用迭代变量来呈现自定义单元格内容?
您可以使用内置指令 NgTemplateOutlet
轻松解决您的问题,该指令允许您将上下文传递给 EmbeddedView
(ng-template
)
先删除DatatableContentDirective
然后更改
中的标记
数据-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>
另请参阅有关模板变量的更多信息 let-name
我正在构建一个数据 table 组件,该组件被设计为非常通用的组件。
想法是将 table 定义为:
<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,我们可以决定属性应该显示table.在内部 table 将按列执行 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”作为一个简单的字符串和一个自定义指令来用相应的 column/row 值替换“$data”。
在数据table 组件中,我在每个 tbody td
passig row
数据和 colum
设置上使用 appDatatableContent
指令(指令仅适用于列设置有模板的情况):
<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;
}
}
}
此外,请注意每个单元格都有 <ng-container *ngIf="!col.template; else col.template">
,因此如果绑定了任何模板,单元格内容将呈现该模板,但问题是如何将参数(特别是行对象)传递给模板因此模板可以使用带有该参数的插值。
查看正在工作的 plunker:https://plnkr.co/edit/84jhiquT5q3OQaCxTa5i
但这似乎不是最好的方法,因为我无法充分利用 angular 的强大功能,因为我只是替换字符串值。
那么,¿如何定义一个动态模板,它可以使用迭代变量来呈现自定义单元格内容?
您可以使用内置指令 NgTemplateOutlet
轻松解决您的问题,该指令允许您将上下文传递给 EmbeddedView
(ng-template
)
先删除DatatableContentDirective
然后更改
中的标记数据-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>
另请参阅有关模板变量的更多信息 let-name