我想构建一个显示列表中项目的UI,其他详细信息显示在列表的其他列中。当一个项目包含子项目时,我可以展开该项目,并将其他行插入到表格中,并且项目的名称将缩进,但其余列将正常显示。
挑战在于通常以递归方式完成树结构。但是,您不能将节点作为子行的父节点,或者它会破坏表。
我能够得到一个概念证明,如下:
<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中插入无关节点的方式执行此操作?
答案 0 :(得分:0)
解决方案是使用<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>
来代替一个独立的组件。
了解详情<ng-template>
和<ng-container>
。