ChatGPT解决这个技术问题 Extra ChatGPT

Angular2 table rows as component

I am experimenting with angular2 2.0.0-beta.0

I have a table and the line content is generated by angular2 this way:

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

Now this works and I want to encapsulate the content into a component "table-line".

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

And in the component, the template has the content.

But now the table does no more work. Which means, the content is no longer shown in columns. In the browser, the inspector shows me that the DOM elements look like this:

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

How can I make this work?


G
Günter Zöchbauer

use existing table elements as selector

The table element doesn't allow <table-line> elements as children and the browser just removes them when it finds them. You can wrap it in a component and still use the allowed <tr> tag. Just use "tr" as selector.

using <template>

<template> should be allowed as well but doesn't yet work in all browsers. Angular2 actually never adds a <template> element to the DOM, but only processes them internally, therefore this can be used in all browsers with Angular2 as well.

Attribute selectors

Another way is to use attribute selectors

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

to be used like

<tr my-tr>

If the parent component includes your custom tr tag it will be used, otherwise it's default browser behavior takes place. You can also add attributes or classes to your component selector like <tr line-item> with a component selector "tr[line-item] " or <tr class="line-item"> with component selector tr.line-item. This way you have full control. I haven't tried any of this myself yet in Angular2, but I'm pretty sure this works.
Is there any real drawback to this? It works fine, however the default settings for tslint direct me to the style guide recommending against this. I dislike turning off recommended linting rules, but as far as I can tell, it seems a fairly arbitrarily style rule and unavoidable in some situations (such as OP's problem)
I'm pretty sure there is no drawback, except that element selectors are way more common and therefore should be the default. If there is a valid case like table elements or <li> or similar, I don't see any reason why not to use it.
Making my component selector use tr[line-item] worked and conforms to Angular Style guide rule STYLE 05-03 that tslint complains against.
It's just a style rule. If using that were a mistake, they would remove support for it entirely instead of creating a style rule. Your use case is exactly why it's actually supported. Just disable the linter rule.
D
DudeOfDoom

I found the example very usefull but it didn't work in the 2,2.3 build, so after much head scratching made it work again with a few small changes.

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(); }
}

Great answer. I just had to add the MyTrComponent to the app.module.ts and works fine.
M
Mark Rajcok

Here's an example using a component with an attribute selector:

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] ];
}

Output:

1   2   3
11  12  13

Of course the template in the MyTrComponent would be more involved, but you get the idea.

Old (beta.0) plunker.


Is it possible to render ng component without root tag? Something like in Knockout.js.
This doesn't work at all(tried with angular 2.3). Error thrown: Error: Uncaught (in promise): Error: Template parse errors: Can't bind to 'myTr' since it isn't a known property of 'tr'.
To make it work you need to add [ ] on Selector. Don't forget that.
R
Ruben Negredo

Adding 'display: contents' to the component style worked out for me.

CSS:

.table-line {
    display: contents;
}

HTML:

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

Why this works?

When instancing a component, angular (after compiling) wraps the content of the component in the DOM as follows:

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

But in order for the table to display properly, the tr tags can't be wrapped by anything.

So, we add display: contents, to this new element. As I understand, what this does is to tell the explorer that this tag should not be rendered, and display the inner content as if there was no wrapping around. So, while the tag still exists, it doesn't affect visually to the table, and the tr tags are treated as if they were direct children of the table tag.

If you'd like to investigate further on how contents works: https://bitsofco.de/how-display-contents-works/


When possible, please make an effort to provide additional explanation instead of just code. Such answers tend to be more useful as they help members of the community and especially new developers better understand the reasoning of the solution, and can help prevent the need to address follow-up questions.
Hi @Rajan , thanks for the tip. I just discovered how contents works, so I didn't want to put there information based on false assumptions... I added the explanation as I understand it, but if someone notice that there's an error on it please feel free to point it out ^^. I also added a link so people can investigate further... One thing I noticed, while it says that this doesn't work on IE11, I tried it out on IE 11.657.18362.0 and it worked fine (but, since I'm using angular, there might be a polyfill somewhere, so I wouldn't guarantee it 100% on other environments)
M
Matsteel

try this

@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{}

关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now