Как передать данные через вложенные ng-контейнеры и ng-шаблоны? - PullRequest
9 голосов
/ 30 апреля 2020

Я создаю модуль с данными и нацеливаюсь на конкретную реализацию. Я хочу иметь возможность импортировать модуль и использовать его компоненты следующим образом:

randomcomponent.component.html

    <datatable [data]="tableData">
      <datatable-column>
        <ng-template let-row="row">
          <label> {{ row.value }} </label>
        </ng-template>
      </datatable-column>
    </datatable>

Вот компоненты из модуля данных:

datatable.component.html (<datatable>)

<table class="datatable">
  <thead>
    <tr>
      <th *ngFor="let header of tableData?.headers">
        {{ header?.title }}
      </th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let row of tableData?.data">
       <ng-container *ngTemplateOutlet="template; context: { row: row }"></ng-container>
    </tr>
  </tbody>
  <tfoot>
  </tfoot>
</table>

column.component.html (<datatable-column>)

<ng-template let-row="row">
  <ng-container *ngTemplateOutlet="template; context: { row: row }"></ng-container>
</ng-template>

Хотя данные не отображаются. Я использовал предыдущий подход с ng-content, но не смог l oop через контент. Отображается только 1 Как я могу закончить с реализацией, которую я ищу? Стоит ли искать другой подход?

ОБНОВЛЕНИЕ: При условии, что мой StackBlitz https://stackblitz.com/edit/angular-4esuor

1 Ответ

4 голосов
/ 03 мая 2020

Ключ ее в том, что вам нужно найти вложенный шаблон во внешних шаблонах, а затем выполнить итерацию этих внешних шаблонов.

вы можете заручиться помощью другой директивы здесь (рекомендуется, но не обязательно, см. ПРИМЕЧАНИЕ ниже), давайте назовем ее директивой datatable-cell, это очень просто, объявить и экспортировать ее:

@Directive({
  selector: '[datatable-cell]'
})
export class DatatableCellDirective {
  constructor(public templateRef: TemplateRef<any>) { }
}

просто предоставляет шаблон ref, больше ничего не делает.

далее, если вы используете директиву, вы добавляете ее во все ваши столбцы к шаблонам (и просто объявляете let-row, если используете $implicit context ... или придерживаетесь let-row="row", если вам нужен явный контекст):

<datatable-column>
  <ng-template datatable-cell let-row>
    <label> {{ row.value }} </label>
  </ng-template>
</datatable-column>

в компоненте столбца, используйте эту директиву, чтобы найти и открыть шаблон ячейки с помощью ContentChild:

@ContentChild(DatatableCellDirective)
cell: DatatableCellDirective

ПРИМЕЧАНИЕ: вы можете сделать это без DatatableCellDirective и просто установите @ContentChild(TemplateRef) cell: TemplateRef<any> в столбце, но это немного менее гибко, и я рекомендую использовать директиву (объяснено ниже).

в компоненте таблицы, найдите столбцы с ContentChildren как их много, Получите их шаблоны ячеек:

@ContentChildren(DatatableColumnComponent) 
columns: QueryList<DatatableColumnComponent>;
cellTemplates: TemplateRef<any>[] = []

// content children available in this hook
ngAfterContentInit() {
  this.cellTemplates = this.columns.toArray().map(c => c.cell.templateRef);

  // like this if not using the cell directive and using TemplateRef directly
  // this.cellTemplates = this.columns.toArray().map(c => c.cell);
}

, затем в вашей таблице html выполните итерации как строк данных, так и шаблонов ячеек, так как вам нужна ячейка, отображаемая для каждого столбца в каждой строке, устанавливая контекст для $implicit здесь, но используйте любой подходящий контекст (например, {row: row} вместо явного контекста):

<tr *ngFor="let row of tableData?.data">
  <ng-container *ngFor="let tpl of cellTemplates">
    <ng-container *ngTemplateOutlet="tpl; context: {$implicit: row}"></ng-container>
  </ng-container>
</tr>

Вы также можете поместить теги <td></td> внутри итерации столбца, чтобы иметь реальные ячейки таблицы, которые применять ширину столбцов.

это довольно гибкая система ... вы можете предусмотреть ее расширение, чтобы вы могли предоставлять настраиваемые заголовки столбцов в столбцах вместе с директивой datatable-header для облегчения, и вы могли бы найти эти Шаблоны в ваших компонентах столбцов и таблиц аналогичны тем, как находятся ячейки, чтобы итерировать и отображать их в строке заголовка. Использование директивы также позволяет вам использовать другие вещи, кроме ng-template, для создания шаблона (например, тег td) и потенциально может позволить вам добавить больше контекста к вашим ячейкам с помощью входных данных.

blitz: https://stackblitz.com/edit/angular-gj5ean

незначительное редактирование, понял, что ContentChildren итеративны, так что вы можете пропустить часть ngAfterContentInit в компоненте таблицы, выполнив:

@ContentChildren(DatatableColumnComponent) 
columns: QueryList<DatatableColumnComponent>;

и просто сделайте это в шаблоне ...

<ng-container *ngFor="let col of columns">
  <ng-container *ngTemplateOutlet="col.cell.templateRef; context: {$implicit: row}"></ng-container>
</ng-container>

, что обеспечивает лучшее обнаружение изменений в случае изменения самих столбцов (например, добавление / удаление столбцов)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...