使用 ng-content 嵌入创建动态转发器
Creating a dynamic repeater with ng-content transclusion
我想要实现的是一个绑定到任意对象数组的通用组件,当每行的视图也由使用的主组件用组件任意定义时,允许动态添加和删除行它。
请注意,MasterComponent
是一个任意组件,可以为不同的页面实现,旨在自包含,不由任何元数据或外部源定义。
到目前为止我有以下组件:
RepeaterComponent 模板:
<input type="button" value="Add" (click)="addRow()">
<div class="repeater" *ngFor="let row of repeaterArray">
<div class="repeaterRow">
<input type="button" value="Remove" (click)="removeRow(row.rowId)">
<ng-content select="row"></ng-content>
</div>
</div>
主组件模板:
<repeater [repeaterArray]="repeaterObj">
<row>
<field-textbox [data]="row.name" [label]="'Name'"></field-textbox>
<field-textbox [data]="row.description" [label]="'Description'"></field-textbox>
</row>
</repeater>
<field-textbox>
组件是一个自定义组件,我用它来封装简单的输入,其中包含我需要使用的一些额外数据。
MasterComponent 包含一个对象,在这个实例中看起来像这样:
repeaterObj = [
{
"rowId": 1,
"name": "First brand",
"description": "First description"
},
{
"rowId": 2,
"name": "Second brand",
"description": "Second description"
},
{
"rowId": 3,
"name": "Third brand",
"description": "Third description"
}
];
这种方法有两个问题我似乎找不到解决方案。
- 当
ngFor
复制模板时,ng-content
选择器对所有行都是相同的,渲染后我只剩下一个 ng-content
包含点。
<field-textbox>
嵌入指令中的 ngFor
声明中没有对 row
变量的引用,因此我无法正确绑定数据。
有没有更好的方法来实现 RepeaterComponent
,让我用最少的精力创建更多新的 MasterComponents
不同的任意结构和不同的模板?
您可以使用 ngTemplateOutlet 来实现它。
以下是实现动态转发器的步骤:
第一步是提供一个TemplateRef
作为RepeaterComponent
:
的子元素
<repeater [repeaterArray]="repeaterObj">
<ng-template>
...
</ng-template>
</repeater>
第二步 是通过@ContentChild
:
在RepeaterComponent
内查询此模板
export class RepeaterComponent {
@ContentChild(TemplateRef) itemTemplate: TemplateRef<any>;
...
第三步是使用ngTemplateOutlet
渲染模板:
@Component({
selector: 'repeater',
template: `
<input type="button" value="Add" (click)="addRow()">
<div class="repeater" *ngFor="let row of repeaterArray">
<div class="repeaterRow">
<input type="button" value="Remove" (click)="removeRow(row.rowId)">
<ng-template <== this line
[ngTemplateOutlet]="itemTemplate"
[ngTemplateOutletContext]="{ $implicit: row }">
</ng-template>
</div>
</div>`
})
export class RepeaterComponent {
@Input() repeaterArray: Array<any>;
@ContentChild(TemplateRef) itemTemplate: TemplateRef<any>;
...
}
第四步是在MasterComponent
中使用对TemplateRef
里面的row
的引用(回到我们的第一步):
<repeater [repeaterArray]="repeaterObj">
<template let-row>
<field-textbox [data]="row.name" [label]="'Name'"></field-textbox>
<field-textbox [data]="row.description" [label]="'Description'"></field-textbox>
</template>
</repeater>
注意:我们正在传递 ngOutletContext
类似 $implicit
属性 的对象。
using the key $implicit in the context object will set it's value as
default.
它的工作原理如下:
[ngTemplateOutletContext]="{ $implicit: row }" ==> <template let-row>
[ngTemplateOutletContext]="{ item: row }" ==> <template let-row="item">
ngOutletContext
仅在 Angular 2.0.0-rc.2
2 版本后可用
你可以试试对应的plunkr(更新到5.0.0)
我想要实现的是一个绑定到任意对象数组的通用组件,当每行的视图也由使用的主组件用组件任意定义时,允许动态添加和删除行它。
请注意,MasterComponent
是一个任意组件,可以为不同的页面实现,旨在自包含,不由任何元数据或外部源定义。
到目前为止我有以下组件:
RepeaterComponent 模板:
<input type="button" value="Add" (click)="addRow()">
<div class="repeater" *ngFor="let row of repeaterArray">
<div class="repeaterRow">
<input type="button" value="Remove" (click)="removeRow(row.rowId)">
<ng-content select="row"></ng-content>
</div>
</div>
主组件模板:
<repeater [repeaterArray]="repeaterObj">
<row>
<field-textbox [data]="row.name" [label]="'Name'"></field-textbox>
<field-textbox [data]="row.description" [label]="'Description'"></field-textbox>
</row>
</repeater>
<field-textbox>
组件是一个自定义组件,我用它来封装简单的输入,其中包含我需要使用的一些额外数据。
MasterComponent 包含一个对象,在这个实例中看起来像这样:
repeaterObj = [
{
"rowId": 1,
"name": "First brand",
"description": "First description"
},
{
"rowId": 2,
"name": "Second brand",
"description": "Second description"
},
{
"rowId": 3,
"name": "Third brand",
"description": "Third description"
}
];
这种方法有两个问题我似乎找不到解决方案。
- 当
ngFor
复制模板时,ng-content
选择器对所有行都是相同的,渲染后我只剩下一个ng-content
包含点。 <field-textbox>
嵌入指令中的ngFor
声明中没有对row
变量的引用,因此我无法正确绑定数据。
有没有更好的方法来实现 RepeaterComponent
,让我用最少的精力创建更多新的 MasterComponents
不同的任意结构和不同的模板?
您可以使用 ngTemplateOutlet 来实现它。
以下是实现动态转发器的步骤:
第一步是提供一个TemplateRef
作为RepeaterComponent
:
<repeater [repeaterArray]="repeaterObj">
<ng-template>
...
</ng-template>
</repeater>
第二步 是通过@ContentChild
:
RepeaterComponent
内查询此模板
export class RepeaterComponent {
@ContentChild(TemplateRef) itemTemplate: TemplateRef<any>;
...
第三步是使用ngTemplateOutlet
渲染模板:
@Component({
selector: 'repeater',
template: `
<input type="button" value="Add" (click)="addRow()">
<div class="repeater" *ngFor="let row of repeaterArray">
<div class="repeaterRow">
<input type="button" value="Remove" (click)="removeRow(row.rowId)">
<ng-template <== this line
[ngTemplateOutlet]="itemTemplate"
[ngTemplateOutletContext]="{ $implicit: row }">
</ng-template>
</div>
</div>`
})
export class RepeaterComponent {
@Input() repeaterArray: Array<any>;
@ContentChild(TemplateRef) itemTemplate: TemplateRef<any>;
...
}
第四步是在MasterComponent
中使用对TemplateRef
里面的row
的引用(回到我们的第一步):
<repeater [repeaterArray]="repeaterObj">
<template let-row>
<field-textbox [data]="row.name" [label]="'Name'"></field-textbox>
<field-textbox [data]="row.description" [label]="'Description'"></field-textbox>
</template>
</repeater>
注意:我们正在传递 ngOutletContext
类似 $implicit
属性 的对象。
using the key $implicit in the context object will set it's value as default.
它的工作原理如下:
[ngTemplateOutletContext]="{ $implicit: row }" ==> <template let-row>
[ngTemplateOutletContext]="{ item: row }" ==> <template let-row="item">
ngOutletContext
仅在 Angular 2.0.0-rc.2
你可以试试对应的plunkr(更新到5.0.0)