我正在使用嵌套的数据编写HTML表组件,这样输出可能如下所示:
<table>
<tr><td>Parent</td></tr>
<tr><td>Child 1</td></tr>
<tr><td>Child 2</td></tr>
<tr><td>Grandchild 1</td></tr>
</table>
我想使用递归组件创建它,如下所示:
<table>
<data-row *ngFor="let row of rows" [row]="row"></data-row>
</table>
数据行:
<tr><td>{{row.name}}</td></tr>
<data-row *ngFor="let child of row.children" [row]="child"></data-row>
但是,这会在表行周围添加一个包装元素,这会破坏表格并且HTML格式无效:
<table>
<data-row>
<tr>...</tr>
<data-row><tr>...</tr></data-row>
</data-row>
</table>
是否可以删除此data-row
包装元素?
一个解决方案:
一种解决方案是使用<tbody data-row...></tbody>
这是我目前正在做的事情,但这会导致嵌套tbody
元素违反W3C规范
其他想法:
我已尝试使用ng-container
,但似乎无法执行<ng-container data-row...></ng-container>
,因此这不是首发。
我还考虑过放弃使用表格,但是使用HTML表格是允许将数据简单复制到电子表格中的唯一方法。
我考虑的最后一个选项是在生成表格之前将数据展平,但是,由于树可以随意展开和折叠,这会导致过度重新渲染或模型非常复杂。
编辑:这是我目前的解决方案(违反规范):http://plnkr.co/edit/LTex8GW4jfcH38D7RB4V?p=preview
答案 0 :(得分:0)
如果您将行组件包装在ng-container中,您应该能够完成它
<tbody>
<ng-container *ngFor="let row of rows; let i = index">
<data-row [row]="row"></data-row>
</ng-container>
</tbody>
@Component({
selector: 'my-app',
template: `
<table>
<ng-container *ngFor="let row of table">
<tbody data-table-row [row]="row"></tbody>
</ng-container>
</table>
`,
})
export class App {
table = [
{
name: 'Parent',
children: [
{
name: 'Child 1'
children: []
},
{
name: 'Child 2'
children: [
{
name: 'Grandchild 1'
children: []
}
]
}
]
}
]
}
@Component({
selector: 'tbody[data-table-row]',
template: `
<tr><td>{{row.name}}</td></tr>
<tbody *ngFor="let child of row.children" data-table-row [row]="child"></tbody>
`
})
export class DataTableRowComponent {
@Input() row: any;
}
答案 1 :(得分:0)
只需使用类或属性作为组件的选择器,并将其应用于表行元素。
@Component({
selector: [data-row],
带
<tr data-row> </tr>
或
@Component({
selector: .data-row,
带
<tr class="data-row"></tr>
编辑 - 我只能使用子组件中的内容投影使其工作,然后在父组件元素内包含td元素。见这里 - https://plnkr.co/edit/CDU3Gn1Fg1sWLtrLCfxw?p=preview
如果您这样做,您可以使用ContentChildren
查询所有行 import { Component, ContentChildren, QueryList } from '@angular/core';
import { DataRowComponent } from './wherever';
你组件中的某个地方......
@ContentChildren(DataRowComponent) rows: QueryList<DataRowComponent>;
将在ngAfterContentInit
中定义ngAfterContentInit() {
console.log(this.rows); <-- will print all the data from each component
}
注意 - 您也可以在自己的模板中拥有递归(是一个单词吗?)的组件。在数据行组件的模板中,您有任意数量的数据行组件。
答案 2 :(得分:0)
发布另一个答案只是为了表明我在说什么......在此之后我会离开你,承诺。嘿。
http://plnkr.co/edit/XcmEPd71m2w841oiL0CF?p=preview
此示例将所有内容呈现为平面结构,但保留嵌套关系。每个项目都有对其父项及其子项数组的引用。
import {Component, NgModule, VERSION, Input} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
@Component({
selector: 'my-app',
template: `
<table *ngIf="tableReady">
<tr *ngFor="let row of flatList" data-table-row [row]="row"> </tr>
</table>
`,
})
export class App {
tableReady = false;
table = [
{
name: 'Parent',
age: 70,
children: [
{
name: 'Child 1',
age: 40,
children: []
},
{
name: 'Child 2',
age: 30,
children: [
{
name: 'Grandchild 1',
age: 10,
children: []
}
]
}
]
}
];
flatList = [];
ngOnInit() {
let flatten = (level : any[], parent? :any ) => {
for (let item of level){
if (parent) {
item['parent'] = parent;
}
this.flatList.push(item);
if (item.children) {
flatten(item.children, item);
}
}
}
flatten(this.table);
this.tableReady = true;
}
}
@Component({
selector: '[data-table-row]',
template: `
<td>{{row.name}}</td><td>{{row.age}}</td>
`
})
export class DataTableRowComponent {
@Input() row: any;
}
&#13;