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>

マスター コンポーネント テンプレート:

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

このアプローチには、解決策が見つからないように見える 2 つの問題があります。

  1. テンプレートを複製すると、セレクターはすべての行で同一になり、レンダリング後にトランスクルージョンポイントが1つだけ残りng-contentます。ngForng-content
  2. トランスクルードされたディレクティブの宣言rowから変数への参照がないため、データを正しくバインドできません。ngFor<field-textbox>

さまざまな任意の構造とさまざまなテンプレートRepeaterComponentをさらに新しく作成するための労力を最小限に抑える、を実装するためのより良いアプローチはありますか?MasterComponents

4

1 に答える 1

19

ngTemplateOutletを使用してそれを実現できます。

動的リピーターを実装する手順は次のとおりです。

最初のステップTemplateRefは、 の子要素としてを提供することRepeaterComponentです:

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

2 番目のステップRepeaterComponentは、このテンプレートをvia内でクエリすることです@ContentChild

export class RepeaterComponent { 
  @ContentChild(TemplateRef) itemTemplate: TemplateRef<any>;
  ...

3 番目のステップ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>;
  ...
}

4 番目のステップrowは、内部への参照を使用することTemplateRefですMasterComponent(最初のステップに戻ります)。

<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">

ngOutletContext2.0.0-rc.2 の Angular 2 バージョン以降でのみ利用可能

対応するplunkrを試すことができます ( 5.0.0に更新)

于 2016-07-27T09:59:15.443 に答える