web-dev-qa-db-ja.com

Angular 4:補間を使用した動的テンプレート

非常に一般的なコンポーネントとして設計されているデータテーブルコンポーネントを構築しています。

アイデアは、テーブルを次のように定義することです。

<app-datatable [items]="currentPageResult">
    <app-datatable-column attribute="id"
                          header="ID"></app-datatable-column>
    <app-datatable-column attribute="name"
                          header="First Name"></app-datatable-column>
    <app-datatable-column attribute="last_name"
                          header="Last Name"></app-datatable-column>
</app-datatable>

このようにして、配列をdatatableコンポーネントに指定でき、datatable-columnsを定義することで、witch属性でテーブルを表示するかどうかを決定できます。内部的には、テーブルはngForby列と別のngForbyアイテムを実行します。

この部分は単純で、今では非常にうまく機能しています。カスタムhtmlコンテンツをtdに入れたい場合は注意が必要です。このようなもの:

<app-datatable [items]="currentPageResult">
    <app-datatable-column attribute="id"
                          header="ID"
                          [template]="titleTemplate">
        <ng-template #titleTemplate>
            <a role="button" [routerLink]="[data.id]">
                {{data.id}}
            </a>
        </ng-template>
    </app-datatable-column>
    <app-datatable-column attribute="name"
                          header="First Name"></app-datatable-column>
    <app-datatable-column attribute="last_name"
                          header="Last Name"></app-datatable-column>
</app-datatable>

反復変数としてdataを使用しているが、実際には機能しないことに注意してください。私がやりたいことを説明しているだけです。

これを解決するために、単純な文字列として「$ data」を使用し、「$ data」を対応する列/行の値に置き換えるカスタムディレクティブを使用しました。

Datatableコンポーネントでは、各tbody tdpassigでappDatatableContentディレクティブを使用してrowデータとcolum設定を使用しています(このディレクティブは、列の設定の場合にのみ適用されます)テンプレートがあります):

<table class="table">
  <thead>
    <tr>
      <th *ngFor="let col of columns" [ngClass]="getColumnHeaderClasses(col)" (click)="onReorder(col)">{{col.header}}</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let row of items.Items">
      <td *ngFor="let col of columns" appDatatableContent [column]="col" [row]="row">
        <ng-container *ngIf="!col.template; else col.template">
          {{row[col.attribute]}}
        </ng-container>
      </td>
    </tr>
  </tbody>
</table>

そして、ディレクティブは基本的に、内部に「$ data」を含む要素を探し、対応する列値の「$ sdata」を次のように置き換えます。

ngAfterViewInit() {
  if (!this.column.template) {
    return;
  }
  const element: HTMLElement = this.element.nativeElement;
  const value = this.row[this.column.attribute];

  const children = element.getElementsByTagName('*');
  const length = children.length;

  for (let i = 0; i < length; i++) {
    const currentNode = children[i];
    if (!currentNode.children || !currentNode.children.length) {
      const originalHTML: string = currentNode.innerHTML;
      const fixedHTML = originalHTML.replace('$data', value);
      currentNode.innerHTML = fixedHTML;
    }
  }
}

また、各セルには<ng-container *ngIf="!col.template; else col.template">があるため、バインドされたテンプレートがある場合、セルのコンテンツはそのテンプレートをレンダリングしますが、問題は、テンプレートが使用できるように引数(具体的には行オブジェクト)をテンプレートに渡す方法です。そのパラメータによる補間。

作業プランカーを参照してください: https://plnkr.co/edit/84jhiquT5q3OQaCxTa5i

しかし、文字列値を置き換えるだけなので、o angular power)を十分に活用できないため、これは最善のアプローチではないようです。

では、¿反復変数を使用してカスタムセルの内容をレンダリングできる動的テンプレートを定義するにはどうすればよいですか?

6
Sergio Girado

組み込みのディレクティブNgTemplateOutletを使用すると、問題を簡単に解決できます。これにより、コンテキストをEmbeddedViewng-template)に渡すことができます。

最初にDatatableContentDirectiveを削除します

次に、マークアップを変更します

data-table.component.html

<td *ngFor="let col of columns">
  <ng-container *ngIf="!col.template; else customTemplate">
     {{row[col.attribute]}}
  </ng-container>
  <ng-template #customTemplate 
     [ngTemplateOutlet]="col.template"
     [ngTemplateOutletContext]="{ col: col, row: row }">
  </ng-template>
</td>

親コンポーネントで使用します

<ng-template #titleTemplate let-col="col" let-row="row">
  <a role="button" ...>
       <b>Custom</b> {{row[col.attribute]}}
  </a>
</ng-template>

プランカーの例

テンプレート変数let-nameの詳細も参照してください。

13
yurzui