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, мы можем решить, какие атрибуты должны отображать таблицу. Внутри таблица будет выполнять ngFor по столбцам и еще один ngFor по элементам.

Эта часть была простой, и теперь она работает очень хорошо, эта вещь становится сложной, когда я хочу, чтобы пользовательский контент 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 я использую директиву appDatatableContent для каждой tbody td передачи данных 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

Но это не кажется лучшим подходом, потому что я не могу получить преимущества большой мощности angular, так как я просто заменяю строковое значение.

Итак, ¿Как я могу определить динамический шаблон, который может использовать переменную итерации для отображения содержимого настраиваемой ячейки?


person Sergio Girado    schedule 14.07.2017    source источник


Ответы (1)


Вы можете легко решить свою проблему, используя встроенную директиву NgTemplateOutlet, которая позволяет передавать контекст в EmbeddedView (ng-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>

Пример Plunker

См. Также дополнительную информацию о переменной шаблона let-name

person yurzui    schedule 15.07.2017
comment
@ThomasFournet Проверьте обновленный плункер next.plnkr.co/edit/kfDD5P3hi4wtiUYp - person yurzui; 19.07.2019