Filas de la tabla Angular2 como componente

99

Estoy experimentando con angular2 2.0.0-beta.0

Tengo una tabla y el contenido de la línea es generado por angular2 de esta manera:

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

Ahora esto funciona y quiero encapsular el contenido en un componente "línea de tabla".

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

Y en el componente, la plantilla tiene el contenido <tr> <td>.

Pero ahora la mesa ya no funciona. Lo que significa que el contenido ya no se muestra en columnas. En el navegador, el inspector me muestra que los elementos DOM se ven así:

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

¿Cómo puedo hacer que esto funcione?

fbenoit
fuente

Respuestas:

110

usar elementos de tabla existentes como selector

El elemento de tabla no permite <table-line>elementos como elementos secundarios y el navegador simplemente los elimina cuando los encuentra. Puede envolverlo en un componente y seguir utilizando la <tr>etiqueta permitida . Úselo "tr"como selector.

utilizando <template>

<template>también debería permitirse, pero aún no funciona en todos los navegadores. Angular2 en realidad nunca agrega un <template>elemento al DOM, sino que solo los procesa internamente, por lo tanto, esto también se puede usar en todos los navegadores con Angular2.

Selectores de atributos

Otra forma es usar selectores de atributos

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

para ser usado como

<tr my-tr>
Günter Zöchbauer
fuente
Entonces crearía mi TableItemComponent con un selector = 'tr'. Pero, ¿cómo se puede usar 'tr' en otros lugares para diferentes problemas?
fbenoit
6
Si el componente principal incluye su tretiqueta personalizada , se utilizará; de lo contrario, se llevará a cabo el comportamiento predeterminado del navegador. También puede agregar atributos o clases a su selector de componentes como <tr line-item>con un selector de componentes "tr[line-item] "o <tr class="line-item">con un selector de componentes tr.line-item. De esta forma tienes el control total. Todavía no he probado nada de esto en Angular2, pero estoy bastante seguro de que funciona.
Günter Zöchbauer
5
¿Existe algún inconveniente real en esto? Trabaja muy bien, sin embargo, los ajustes por defecto para tslintmí directo a la guía de estilo de recomendar en contra de esto. No me gusta desactivar las reglas de pelusa recomendadas, pero por lo que puedo decir, parece una regla de estilo bastante arbitraria e inevitable en algunas situaciones (como el problema de OP)
Rob
1
Estoy bastante seguro de que no hay ningún inconveniente, excepto que los selectores de elementos son mucho más comunes y, por lo tanto, deberían ser los predeterminados. Si hay un caso válido como elementos de tabla <li>o similar, no veo ninguna razón para no usarlo.
Günter Zöchbauer
2
Hacer que mi selector de componentes use tr [elemento de línea] funcionó y se ajusta a la regla de la guía de estilo angular STYLE 05-03 contra la que tslint se queja.
CM
30

Encontré el ejemplo muy útil, pero no funcionó en la versión 2,2.3, así que después de mucho rascar la cabeza lo hice funcionar nuevamente con algunos pequeños cambios.

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
fuente
1
Gran respuesta. Solo tuve que agregar MyTrComponentel app.module.tsy funciona bien.
Tito Leiva
26

A continuación, se muestra un ejemplo que utiliza un componente con un selector de atributos:

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

Salida:

1   2   3
11  12  13

Por supuesto, la plantilla en MyTrComponent sería más complicada, pero entiendes la idea.

Antiguo (beta.0) plunker .

Mark Rajcok
fuente
¿Es posible renderizar el componente ng sin etiqueta raíz? Algo como <! - / ko -> en Knockout.js.
Ssss
@PashaPasha, consulte stackoverflow.com/questions/34280475/…
Mark Rajcok
14
Esto no funciona en absoluto (probado con angular 2.3). Error lanzado:Error: Uncaught (in promise): Error: Template parse errors: Can't bind to 'myTr' since it isn't a known property of 'tr'.
Vukasin
Para que funcione, debe agregar [] en Selector. No lo olvides.
Después del
6

Agregar 'display: contents' al estilo del componente funcionó para mí.

CSS:

.table-line {
    display: contents;
}

HTML:

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

¿Por qué funciona esto?

Al crear una instancia de un componente, angular (después de compilar) envuelve el contenido del componente en el DOM de la siguiente manera:

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

Pero para que la tabla se muestre correctamente, las tretiquetas no pueden estar envueltas por nada.

Entonces, agregamos display: contents, a este nuevo elemento. Según tengo entendido, lo que esto hace es decirle al explorador que esta etiqueta no debe procesarse y mostrar el contenido interno como si no hubiera ningún ajuste. Por lo tanto, aunque la etiqueta aún existe, no afecta visualmente a la tabla y las tretiquetas se tratan como si fueran hijos directos de latable etiqueta.

Si desea investigar más sobre cómo funcionan los contenidos: https://bitsofco.de/how-display-contents-works/

Ruben Negredo
fuente
1
Cuando sea posible, haga un esfuerzo por proporcionar una explicación adicional en lugar de solo el código. Estas respuestas tienden a ser más útiles ya que ayudan a los miembros de la comunidad y especialmente a los nuevos desarrolladores a comprender mejor el razonamiento de la solución y pueden ayudar a evitar la necesidad de abordar preguntas de seguimiento.
Rajan
Hola @Rajan, gracias por el dato. Acabo de descubrir cómo contentsfunciona, así que no quería poner allí información basada en suposiciones falsas ... Agregué la explicación tal como la entiendo, pero si alguien nota que hay un error, no dude en señalarlo ^ ^. También agregué un enlace para que la gente pueda investigar más ... Una cosa que noté, aunque dice que esto no funciona en IE11, lo probé en IE 11.657.18362.0 y funcionó bien (pero, ya que estoy usando angular, podría haber un polyfill en alguna parte, por lo que no lo garantizaría al 100% en otros entornos)
Ruben Negredo
Muy buena respuesta. En mi opinión, esto debería aceptarse.
adamsfamily
-3

prueba esto

@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
fuente