创建具有ng-content包含的动态转发器 [英] Creating a dynamic repeater with ng-content transclusion

查看:92
本文介绍了创建具有ng-content包含的动态转发器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

  1. ngFor复制模板时,所有行中的ng-content选择器都相同,该模板在渲染后仅留下一个ng-content包含点.
  2. <field-textbox>转换指令中没有引用ngFor声明中的row变量,因此我无法正确绑定数据.
  1. The ng-content selector is identical for all the rows when the ngFor duplicates the template which leaves me with only one ng-content transclusion point after rendering.
  2. There is no reference to the row variable from the ngFor 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>

第二步是通过@ContentChildRepeaterComponent中查询此模板:

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>;
  ...
}

第四步是使用对MasterComponentTemplateRefTemplateRef内部的引用(只是回到我们的第一步):

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆