Angular2表格行作为组件

120

我正在尝试使用angular2 2.0.0-beta.0进行实验。

我有一个表格,行内容是通过angular2以如下方式生成的:

    <table>
        <tr *ngFor="#line of data">
            .... content ....
        </tr>
    </table>

现在这段代码可以工作,我想将其封装成一个组件 "table-line"。

    <table>
        <table-line *ngFor="#line of data" [data]="line">
        </table-line>
    </table>

并且在组件中,模板包含<tr><td>内容。

但是现在表格不再起作用了。这意味着内容不再以列的形式显示。 在浏览器中,检查器向我展示DOM元素如下:

    <table>
        <table-line ...>
            <tbody>
                <tr> ....

我该如何让这个工作起来?

5个回答

140

使用现有的表元素作为选择器

表元素不允许将<table-line>元素用作其子元素,当浏览器发现它们时会将其移除。您可以将其包装在组件中,仍然可以使用允许的<tr>标签。只需使用"tr"作为选择器。

使用<template>

<template>也应该被允许,但并非所有浏览器都支持它。Angular2实际上从不向DOM添加<template>元素,而是仅在内部处理它们,因此在使用Angular2的所有浏览器中也可以使用它。

属性选择器

另一种方法是使用属性选择器。

@Component({
  selector: '[my-tr]',
  ...
})

可用于

<tr my-tr>

6
如果父组件包含您的自定义tr标记,则会使用它,否则将使用默认浏览器行为。您还可以向组件选择器添加属性或类,例如<tr line-item>与组件选择器"tr[line-item]"<tr class="line-item">与组件选择器tr.line-item。这样,您就可以完全掌控。我还没有在Angular2中尝试过这些内容,但我相信这是有效的。 - Günter Zöchbauer
7
这是否存在任何实质性的缺点?这个方法很有效,但是tslint的默认设置指向了样式指南,该指南建议不要采用这种方法。我不喜欢关闭推荐的代码检查规则,但据我所知,这似乎是一个相当武断的样式规则,在某些情况下是无法避免的(例如 OP 的问题)。 - Rob
1
我非常确定没有任何缺点,除了元素选择器更常见,因此应该是默认选择。如果有像表格元素或<li>等有效的情况,我不认为有任何理由不使用它。 - Günter Zöchbauer
4
使用 tr[line-item] 修饰符来选择我的组件选择器是可行的,并且符合 Angular 风格指南规则 STYLE 05-03,这也避免了 tslint 的警告。 - C.M.
1
这只是一条样式规则。如果使用它是错误的,他们会完全删除对其的支持,而不是创建一个样式规则。您的用例正是为什么它被支持的原因。只需禁用linter规则即可。 - Günter Zöchbauer
显示剩余5条评论

34

我发现这个例子非常有用,但在2.2.3版本中它不能运行,因此经过长时间的思考后,我进行了一些小的更改,使它再次正常运行。

import {Component, Input} from '@angular/core'

@Component({
  selector: "[my-tr]",
  template: `<td *ngFor='let item of row'>{{item}}</td>`    
})
export class MyTrComponent {
  @Input("line") row:any;
}

@Component({
  selector: "my-app",
  template: `<h1>{{title}}</h1>
  <table>
    <tr  *ngFor="let line of data" my-tr [line]="line"></tr>
  </table>`

})
export class AppComponent {

  title = "Angular 2 - tr attribute selector!";
  data = [ [1,2,3], [11, 12, 13] ];
  constructor() { console.clear(); }
}

1
非常好的答案。我只需要将 MyTrComponent 添加到 app.module.ts 中,就可以正常工作了。 - Tito Leiva

28

这是一个使用属性选择器的组件示例:

import {Component, Input} from '@angular/core';
@Component({
  selector: '[myTr]',
  template: `<td *ngFor="let item of row">{{item}}</td>`
})
export class MyTrComponent {
  @Input('myTr') row;
}
@Component({
  selector: 'my-app',
  template: `{{title}}
  <table>
    <tr *ngFor="let line of data" [myTr]="line"></tr>
  </table>
  `
})
export class AppComponent {
  title = "Angular 2 - tr attribute selector";
  data = [ [1,2,3], [11, 12, 13] ];
}

输出:

1   2   3
11  12  13

当然,MyTrComponent中的模板会更加复杂,但你已经有了想法。

旧版(beta.0)plunker


在Angular中是否有可能在组件渲染时不使用根标签呢?就像在Knockout.js中的<!-- /ko -->那样。 - Ssss
@PashaPasha,请查看https://dev59.com/VFsX5IYBdhLWcg3wDr88。 - Mark Rajcok
14
这完全不起作用(尝试了 angular 2.3)。出现错误:Can't bind to 'myTr' since it isn't a known property of 'tr'.``` 意思是:无法将'myTr'绑定到'tr',因为它不是'tr'的已知属性。 - Vukasin
为使其工作,您需要在选择器上添加[ ]。别忘了这一点。 - AFetter

25

将"display: contents"添加到组件样式中对我很有效。

CSS:

.table-line {
    display: contents;
}

HTML:

<table>
    <table-line class="table-line" [data]="line">
    </table-line>
</table>

为什么这些能够工作?

在创建一个组件的实例时,Angular 会在编译后将组件内容包装为 DOM 如下:

<table>
    <table-line>
        <tr></tr>
    </table-line>
</table>

但是为了让表格正确显示,tr标签不能被任何东西包裹。

因此,我们向这个新元素添加display: contents。据我所知,这样做是告诉浏览器不要呈现此标签,并像没有包裹一样显示其中的内容。因此,虽然标签仍然存在,但它对表格没有视觉影响,tr标签被视为直接是table标签的子级。

如果您想进一步了解如何使用contents,请参阅: https://bitsofco.de/how-display-contents-works/


1
尽可能地,请努力提供额外的解释,而不仅仅是代码。这样的答案往往更有用,因为它们帮助社区成员,特别是新开发人员更好地理解解决方案的原因,并可以帮助防止需要回答后续问题的需要。 - Rajan
1
嗨@Rajan,谢谢你的提示。我刚刚发现了contents的工作原理,所以我不想基于错误的假设放置信息...我添加了我理解的解释,但如果有人注意到有错误,请随时指出^^。我还添加了一个链接,让人们可以进一步调查...我注意到一件事,虽然它说这在IE11上不起作用,但我在IE 11.657.18362.0上尝试了一下,它运行得很好(但是,由于我正在使用angular,可能会有某个polyfill,因此我不能保证在其他环境中百分之百地保证它能正常工作)。 - Ruben Negredo

-3

试一下这个

@Component({
    selecctor: 'parent-selector',
    template: '<table><body><tra></tra></body></table>'
    styles: 'tra{ display:table-row; box-sizing:inherit; }'
})
export class ParentComponent{
}

@Component({
    selecctor: 'parent-selector',
    template: '<td>Name</td>Date<td></td><td>Stackoverflow</td>'
})
export class ChildComponent{}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接