使用ng-content transclusion创建动态转发器

时间:2016-07-27 07:57:10

标签: angular angular2-ngcontent

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

请注意,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. row已转换指令中的ngFor声明中没有引用<field-textbox>变量,因此我无法正确绑定数据。
  3. 有没有更好的方法来实现RepeaterComponent,这会给我最少的努力来创建更多新的MasterComponents不同的任意结构和不同的模板?

1 个答案:

答案 0 :(得分:11)

您可以使用ngTemplateOutlet来实现它。

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

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

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

第二步是通过RepeaterComponent@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>;
  ...
}

第四步是使用rowTemplateRefMasterComponent的引用(仅回到我们的第一步):

<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对象。

  

使用上下文对象中隐含的键$将其值设置为   默认值。

它的工作原理如下:

[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