Angular 2:删除组件中的包装DOM元素

时间:2017-08-25 15:17:22

标签: html angular html-table

我正在使用嵌套的数据编写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

3 个答案:

答案 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

此示例将所有内容呈现为平面结构,但保留嵌套关系。每个项目都有对其父项及其子项数组的引用。

&#13;
&#13;
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;
&#13;
&#13;