Я хочу создать пользовательский интерфейс, который отображает элементы в списке, с дополнительными сведениями, отображаемыми в других столбцах в списке. Когда элемент содержит дочерние элементы, я могу развернуть элемент, а дополнительные строки будут вставлены в таблицу, а имена элементов будут отступы, но остальные столбцы отображаются нормально.
Проблема состоит в том, что обычно древовидная структура выполняется рекурсивно. Но вы не можете, чтобы узел служил родителем дочерних строк, или он разбивает таблицу.
Я смог получить доказательство концепции, например:
<table>
<thead>
<th>Item Name</th>
<th>Summary</th>
<th>Priority</th>
</thead>
<ng-template ngFor let-root [ngForOf]="['a','b','c']">
<tr>
<td style="padding-left: 0;">{{root}}</td>
<td>Summary for {{root}}</td>
<td>None</td>
</tr>
<ng-template ngFor let-child [ngForOf]="['1','2','3']">
<tr>
<td style="padding-left: 1em;">{{child}}</td>
<td>Summary for {{child}}</td>
<td>None</td>
</tr>
</ng-template>
</ng-template>
</table>
Это работает, потому что <ng-template>
не отображается как узел в DOM.
Затем я попытался создать компонент для представления этой концепции:
<tr>
<td style="padding-left: calc({{depth}}*1em);">
{{item.nodeName()}}
</td>
<td *ngIf="details">{{item.summary}}</td>
<td *ngIf="details">{{item.priority_name}}</td>
</tr>
<tr *ngIf="loading">
<td *ngIf="details" style="padding-left: calc({{depth+1}}*1em);" colspan=3>Loading...</td>
<td *ngIf="! details" style="padding-left: calc({{depth+1}}*1em);">Loading...</td>
</tr>
<ng-template ngFor let-child [ngForOf]="item.children">
<item-node [item]="child" depth="depth+1" [details]="details"></item-node>
</ng-template>
К сожалению, это не работает, потому что <item-node>
создает узел в DOM, который разбивает таблицу.
Есть ли способ сделать это таким образом, чтобы не вставлять посторонние узлы в DOM?
Решение состоит в использовании <ng-template>
и <ng-container>
, чтобы создать рекурсивный шаблон, например:
<ng-template #node>
<tr><!-- current node --></tr>
<ng-container *ngIf="expanded">
<ng-container ngFor let-child [ngForOf]="children">
<ng-container *ngTemplateOutlet="node; context:child"></ng-container>
</ng-container>
</ng-container>
</ng-template>
<table>
<thead><!-- column headers --></thead>
<ng-container *ngTemplateOutlet="node; context: root"></ng-container>
</table>
Есть более подробная информация, которая должна быть разработана, например, как сделать отступ работы (вам нужно следить за глубиной и добавлять стиль, отступы на основе глубины), вам нужно передать переменные, которые нужно вытащить из контекста и т.д. Но проблема с корнем, как избежать ненужных элементов в DOM, решается с помощью <ng-container>
а дочерние узлы обрабатываются с помощью рекурсивного <ng-template>
вместо stand- один компонент.
Подробнее читайте в <ng-template>
и <ng-container>
.