10

我想要实现的是一个绑定到任意对象数组的通用组件,当每行的视图也由使用它的主组件任意定义时,它允许动态添加和删除行。

请注意,这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>

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>组件是一个自定义组件,我用它来封装简单的输入,其中包含一些我需要使用的附加数据。

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"
}
];

这种方法有两个问题,我似乎无法找到解决方案。

  1. ng-content当复制模板时,所有行的选择器都是相同的,这使我在渲染后ngFor只有一个嵌入点。ng-content
  2. transcluded 指令中的声明中没有对row变量的引用,因此我无法正确绑定数据。ngFor<field-textbox>

有没有更好的方法来实现,RepeaterComponent这将使我创建更多MasterComponents不同的任意结构和不同模板的新工作量最少?

4

1 回答 1

19

您可以使用ngTemplateOutlet来实现它。

以下是实现动态转发器的步骤:

第一步是提供 aTemplateRef作为 的子元素RepeaterComponent

<repeater [repeaterArray]="repeaterObj">
  <ng-template>
    ...
  </ng-template>
</repeater>

第二步是在RepeaterComponentvia中查询这个模板@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>;
  ...
}

第四步是使用row内部引用(回到我们TemplateRefMasterComponent第一步):

<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属性的对象。

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

它的工作原理如下:

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

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

ngOutletContext仅在 Angular 2 版本 2.0.0-rc.2 之后可用

你可以试试对应的plunkr (更新到5.0.0 )

于 2016-07-27T09:59:15.443 回答