Angular 2:删除组件中的包装 DOM 元素
Posted
技术标签:
【中文标题】Angular 2:删除组件中的包装 DOM 元素【英文标题】:Angular 2: Remove the wrapping DOM element in a component 【发布时间】:2018-02-03 16:36:06 【问题描述】:我正在编写一个使用嵌套数据的 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 表格是允许将数据简单复制到电子表格中的唯一方法,这是必需的。
我考虑的最后一个选项是在生成表格之前将数据展平,但是,由于树可以随意展开和折叠,这会导致过度重新渲染或非常复杂的模型。
编辑:这是我当前解决方案的 Plunk(违反规范):http://plnkr.co/edit/LTex8GW4jfcH38D7RB4V?p=preview
【问题讨论】:
【参考方案1】:发布另一个答案只是为了表明我在说什么......在此之后我会让你一个人呆着,保证。呵呵。
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;
【讨论】:
【参考方案2】:只需使用类或属性作为组件的选择器并将其应用于表格行元素。
@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
注意 - 您还可以在自己的模板中拥有递归(这是一个词吗?)自己的组件。在数据行组件的模板中,您可以有任意数量的数据行组件。
【讨论】:
问题是您不能将一个tr
嵌套在另一个内部,而您的解决方案会导致此问题。我用 Plunk 更新了我的答案,显示了我想要实现的目标。
我不确定我上面提到的解决方案将如何导致嵌套 tr 元素,除非你按照我在底部的注释中所说的做了?不过,我并不是在为您的解决方案建议底部的注释,而只是将其作为一般提示。
在此处查看 plunker - plnkr.co/edit/CDU3Gn1Fg1sWLtrLCfxw?p=preview 如果您使用内容投影并将 td 元素包含在父模板中的组件内部而不是组件模板中,它似乎可以工作。这告诉我浏览器不会正确解释表格标签,除非所有必需的标签都在同一个模板中。所以尝试使用 ng-content
我已经按照您的建议编辑了我的示例。如您所见,该表不再有效! plnkr.co/edit/cDWaIo5kAaveSLCERdjM?p=preview
因为您使用 tr 作为组件的元素...但随后立即将 tr 元素再次放入子 component.template 作为其第一个元素。【参考方案3】:
如果你将行组件包装在一个 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;
【讨论】:
这导致<data-row><tr>...</tr></data-row>
是无效的 HTML
它在data-row
内部,请参阅tbody
方法的示例:plnkr.co/edit/LTex8GW4jfcH38D7RB4V?p=preview
问题是,它不保存表格。见这里:plnkr.co/edit/qNqomFUr2h47YeuiosHs?p=preview
@Josh,你能成功吗?我有一个带有 的解决方案和另一个带有 table 的解决方案,但还没有发布。如果你有兴趣,我会
还没有运气。我将不胜感激更多的解决方案以上是关于Angular 2:删除组件中的包装 DOM 元素的主要内容,如果未能解决你的问题,请参考以下文章
Angular2 通知组件关于在 Angular 之外创建的 DOM 元素
如何将 DOM 附加到 Angular 2 组件并仍然获得封装样式