创建具有ng-content包含的动态转发器 [英] Creating a dynamic repeater with ng-content transclusion
问题描述
我想要实现的是一个绑定到任意对象数组的通用组件,当每行的视图也由使用它的主组件随组件任意定义时,允许动态添加和删除行.
What I'm trying to achieve is a generic component that is bound to an array of arbitrary objects that allows adding and removing rows dynamically when the view of each row is also arbitrarily defined with components by a master component that uses it.
请注意,MasterComponent
是一个任意组件,可以在不同的页面上实现,并且旨在独立存在,并且不受任何元数据或外部源的定义.
Note that MasterComponent
is an arbitrary component that would be implemented for different pages and is intended to be self contained and not defined by any metadata or external source.
到目前为止,我拥有以下组件:
What I have so far are the following Components:
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>
MasterComponent模板:
<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>
组件是一个自定义组件,用于封装简单的输入,这些输入包含一些我需要使用的其他数据.
The <field-textbox>
component is a custom component that I use to encapsulate simple inputs that holds some additional data that I need to use.
MasterComponent 包含一个对象,该对象看起来像这样:
The MasterComponent holds an object that for this instance looks like this:
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"
}
];
这种方法有两个问题,我似乎无法解决.
This approach has two issues that I can't seem to find a solution for.
- 当
ngFor
复制模板时,所有行中的ng-content
选择器都相同,该模板在渲染后仅留下一个ng-content
包含点. - 在
<field-textbox>
转换指令中没有引用ngFor
声明中的row
变量,因此我无法正确绑定数据.
- The
ng-content
selector is identical for all the rows when thengFor
duplicates the template which leaves me with only oneng-content
transclusion point after rendering. - There is no reference to the
row
variable from thengFor
declaration in the<field-textbox>
transcluded directives so I can't bind the data correctly.
是否有更好的方法来实现RepeaterComponent
,这将使我花费最少的精力来创建更多具有不同任意结构和不同模板的新MasterComponents
?
Is there a better approach to implement the RepeaterComponent
that would give me the least amount of effort to create more new MasterComponents
of different arbitrary structures and different templates?
推荐答案
您可以使用以下是实现动态转发器的步骤:
Following are the steps in implementing dynamic repeater:
第一步是提供TemplateRef
作为RepeaterComponent
的子元素:
First step is to provide a TemplateRef
as a child element of the RepeaterComponent
:
<repeater [repeaterArray]="repeaterObj">
<ng-template>
...
</ng-template>
</repeater>
第二步是通过@ContentChild
在RepeaterComponent
中查询此模板:
Second step is to query this template within RepeaterComponent
via @ContentChild
:
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
内TemplateRef
内部的引用(只是回到我们的第一步):
Fourth step is to use reference to the row
inside TemplateRef
within MasterComponent
(just back to our first step):
<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
属性的对象.
Notice: we are passing ngOutletContext
like object with $implicit
property.
在上下文对象中使用键$ 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版本2.0.0-rc.2起可用
ngOutletContext
is availlable only since Angular 2 version of 2.0.0-rc.2
您可以尝试相应的 plunkr (已更新为 5.0.0 )
这篇关于创建具有ng-content包含的动态转发器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!