Linhas da tabela Angular2 como componente

99

Estou experimentando o angular2 2.0.0-beta.0

Eu tenho uma tabela e o conteúdo da linha é gerado pelo angular2 desta forma:

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

Agora isso funciona e eu quero encapsular o conteúdo em um componente "linha de tabela".

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

E no componente, o template possui o conteúdo <tr> <td>.

Mas agora a mesa não funciona mais. O que significa que o conteúdo não é mais mostrado em colunas. No navegador, o inspetor me mostra que os elementos DOM têm a seguinte aparência:

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

Como posso fazer isso funcionar?

fbenoit
fonte

Respostas:

110

usar elementos de tabela existentes como seletor

O elemento da tabela não permite <table-line>elementos como filhos e o navegador apenas os remove quando os encontra. Você pode envolvê-lo em um componente e ainda usar a <tr>tag permitida . Use apenas "tr"como seletor.

usando <template>

<template>também deve ser permitido, mas ainda não funciona em todos os navegadores. Na verdade, o Angular2 nunca adiciona um <template>elemento ao DOM, mas apenas os processa internamente, portanto, isso pode ser usado em todos os navegadores com Angular2 também.

Seletores de atributos

Outra maneira é usar seletores de atributo

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

para ser usado como

<tr my-tr>
Günter Zöchbauer
fonte
Então, eu criaria meu TableItemComponent com um seletor = 'tr'. Mas como usar 'tr' em outros lugares para questões diferentes?
fbenoit
6
Se o componente pai inclui o seu costume trtag será usado, caso contrário é o comportamento padrão do navegador ocorre. Você também pode adicionar atributos ou classes ao seu seletor de componente como <tr line-item>com um seletor de componente "tr[line-item] "ou <tr class="line-item">com um seletor de componente tr.line-item. Dessa forma, você tem controle total. Ainda não tentei nada disso no Angular2, mas tenho certeza de que funciona.
Günter Zöchbauer
5
Existe alguma desvantagem real nisso? Funciona bem, porém as configurações padrão tslintdirecionam-me para o guia de estilo que recomenda contra isso. Não gosto de desligar as regras de linting recomendadas, mas pelo que posso dizer, parece uma regra de estilo bastante arbitrário e inevitável em algumas situações (como o problema de OP)
Rob
1
Tenho certeza de que não há nenhuma desvantagem, exceto que os seletores de elemento são muito mais comuns e, portanto, devem ser o padrão. Se houver um caso válido como elementos de tabela <li>ou similares, não vejo razão para não usá-lo.
Günter Zöchbauer
2
Fazer meu seletor de componente usar tr [item de linha] funcionou e está em conformidade com a regra do guia de estilo angular ESTILO 05-03 da qual tslint reclama.
CM de
30

Achei o exemplo muito útil, mas ele não funcionou na compilação 2.2.3, então depois de muito mexer na cabeça, ele voltou a funcionar com algumas pequenas alterações.

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(); }
}
DudeOfDoom
fonte
1
Ótima resposta. Eu só tive que adicionar o MyTrComponentao app.module.tse funciona bem.
Tito Leiva
26

Aqui está um exemplo de uso de um componente com um seletor de atributo:

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

Resultado:

1   2   3
11  12  13

Claro que o modelo no MyTrComponent seria mais envolvido, mas você entendeu.

Velho (beta.0) Plunker .

Mark Rajcok
fonte
É possível renderizar o componente ng sem tag raiz? Algo como <! - / ko -> em Knockout.js.
Ssss de
@PashaPasha, consulte stackoverflow.com/questions/34280475/…
Mark Rajcok
14
Isso não funciona de jeito nenhum (tentei com o angular 2.3). Erro gerado:Error: Uncaught (in promise): Error: Template parse errors: Can't bind to 'myTr' since it isn't a known property of 'tr'.
Vukasin
Para fazer funcionar, você precisa adicionar [] no Seletor. Não se esqueça disso.
Carta de
6

Adicionar 'display: contents' ao estilo de componente funcionou para mim.

CSS:

.table-line {
    display: contents;
}

HTML:

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

Por que isso funciona?

Ao criar a instância de um componente, angular (após compilar) envolve o conteúdo do componente no DOM da seguinte maneira:

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

Mas, para que a tabela seja exibida corretamente, as trtags não podem ser envolvidas por nada.

Então, nós adicionamos display: contents, a este novo elemento. Pelo que entendi, o que isso significa é dizer ao explorador que essa tag não deve ser renderizada e exibir o conteúdo interno como se não houvesse enrolamento. Portanto, enquanto a tag ainda existe, ela não afeta visualmente a tabela, e as trtags são tratadas como se fossem filhos diretos da tabletag.

Se você gostaria de investigar mais sobre como o conteúdo funciona: https://bitsofco.de/how-display-contents-works/

Ruben Negredo
fonte
1
Quando possível, faça um esforço para fornecer uma explicação adicional em vez de apenas código. Essas respostas tendem a ser mais úteis porque ajudam os membros da comunidade, especialmente os novos desenvolvedores, a entender melhor o raciocínio da solução e podem ajudar a evitar a necessidade de responder a perguntas de acompanhamento.
Rajan
Olá @Rajan, obrigado pela dica. Acabei de descobrir como contentsfunciona, então não queria colocar lá informações baseadas em falsas suposições ... Eu adicionei a explicação como a entendi, mas se alguém perceber que há um erro nela, fique à vontade para apontá-lo ^ ^. Eu também adicionei um link para que as pessoas possam investigar mais ... Uma coisa eu percebi, embora ele diga que isso não funciona no IE11, eu tentei no IE 11.657.18362.0 e funcionou bem (mas, como estou usando angular, pode haver um polyfill em algum lugar, então eu não garantiria 100% em outros ambientes)
Ruben Negredo
Muito boa resposta. IMO isso deve ser aceito.
adamsfamily
-3

tente isso

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