Lignes de table Angular2 en tant que composant

99

J'expérimente angular2 2.0.0-beta.0

J'ai une table et le contenu de la ligne est généré par angular2 de cette façon:

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

Maintenant, cela fonctionne et je souhaite encapsuler le contenu dans un composant "table-line".

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

Et dans le composant, le modèle a le contenu <tr> <td>.

Mais maintenant, la table ne fonctionne plus. Ce qui signifie que le contenu n'est plus affiché dans les colonnes. Dans le navigateur, l'inspecteur me montre que les éléments DOM ressemblent à ceci:

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

Comment puis-je faire fonctionner cela?

fbenoit
la source

Réponses:

110

utiliser les éléments de table existants comme sélecteur

L'élément table n'autorise pas les <table-line>éléments en tant qu'enfants et le navigateur les supprime simplement lorsqu'il les trouve. Vous pouvez l'envelopper dans un composant tout en utilisant la <tr>balise autorisée . Utilisez simplement "tr"comme sélecteur.

en utilisant <template>

<template>devrait également être autorisé mais ne fonctionne pas encore dans tous les navigateurs. Angular2 n'ajoute en fait jamais d' <template>élément au DOM, mais ne les traite qu'en interne, ce qui peut donc être utilisé dans tous les navigateurs avec Angular2.

Sélecteurs d'attributs

Une autre façon consiste à utiliser des sélecteurs d'attributs

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

à utiliser comme

<tr my-tr>
Günter Zöchbauer
la source
Donc je créerais mon TableItemComponent avec un selector = 'tr'. Mais comment utiliser «tr» dans d'autres endroits pour différents problèmes?
fbenoit
6
Si le composant parent inclut votre trbalise personnalisée, il sera utilisé, sinon c'est le comportement par défaut du navigateur. Vous pouvez également ajouter des attributs ou des classes à votre sélecteur de composants comme <tr line-item>avec un sélecteur de composants "tr[line-item] "ou <tr class="line-item">avec un sélecteur de composants tr.line-item. De cette façon, vous avez un contrôle total. Je n'ai encore essayé rien de tout cela moi-même dans Angular2, mais je suis presque sûr que cela fonctionne.
Günter Zöchbauer le
5
Y a-t-il un réel inconvénient à cela? Il fonctionne très bien, mais les paramètres par défaut pour tslintmoi directement au guide de style recommandant contre cela. Je n'aime pas désactiver les règles de peluchage recommandées, mais pour autant que je sache, cela semble une règle de style assez arbitraire et inévitable dans certaines situations (comme le problème d'OP)
Rob
1
Je suis presque sûr qu'il n'y a aucun inconvénient, sauf que les sélecteurs d'éléments sont beaucoup plus courants et devraient donc être la valeur par défaut. S'il y a un cas valide comme les éléments de table ou <li>ou similaire, je ne vois aucune raison de ne pas l'utiliser.
Günter Zöchbauer
2
Faire en sorte que mon sélecteur de composants utilise tr [ligne-élément] a fonctionné et est conforme à la règle du guide de style angulaire STYLE 05-03 contre laquelle tslint se plaint.
CM
30

J'ai trouvé l'exemple très utile mais il n'a pas fonctionné dans la version 2.2.3, donc après beaucoup de grattage à la tête, il a fonctionné à nouveau avec quelques petits changements.

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
la source
1
Très bonne réponse. Je devais juste ajouter le MyTrComponentà app.module.tset fonctionne très bien.
Tito Leiva
26

Voici un exemple d'utilisation d'un composant avec un sélecteur d'attribut:

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

Production:

1   2   3
11  12  13

Bien sûr, le modèle dans MyTrComponent serait plus impliqué, mais vous voyez l'idée.

Vieux (beta.0) plunker .

Mark Rajcok
la source
Est-il possible de rendre le composant ng sans balise racine? Quelque chose comme <! - / ko -> dans Knockout.js.
Ssss
@PashaPasha, voir stackoverflow.com/questions/34280475/…
Mark Rajcok
14
Cela ne fonctionne pas du tout (essayé avec angular 2.3). Erreur lancée:Error: Uncaught (in promise): Error: Template parse errors: Can't bind to 'myTr' since it isn't a known property of 'tr'.
Vukasin le
Pour que cela fonctionne, vous devez ajouter [] sur le sélecteur. N'oublie pas ça.
AFetter le
6

L'ajout de «affichage: contenu» au style du composant a fonctionné pour moi.

CSS:

.table-line {
    display: contents;
}

HTML:

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

Pourquoi ça marche?

Lors de l'instanciation d'un composant, angular (après la compilation) encapsule le contenu du composant dans le DOM comme suit:

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

Mais pour que le tableau s'affiche correctement, le tr balises ne peuvent être enveloppées par rien.

Donc, nous ajoutons display: contents, à ce nouvel élément. Si je comprends bien, cela indique à l'explorateur que cette balise ne doit pas être rendue et affiche le contenu interne comme s'il n'y avait pas de retour à la ligne. Ainsi, tant que la balise existe toujours, elle n'affecte pas visuellement la table, et les trbalises sont traitées comme si elles étaient des enfants directs dutable balise.

Si vous souhaitez en savoir plus sur le fonctionnement du contenu: https://bitsofco.de/how-display-contents-works/

Ruben Negredo
la source
1
Lorsque cela est possible, faites un effort pour fournir des explications supplémentaires au lieu de simplement du code. Ces réponses ont tendance à être plus utiles car elles aident les membres de la communauté et en particulier les nouveaux développeurs à mieux comprendre le raisonnement de la solution, et peuvent aider à éviter d'avoir à répondre aux questions de suivi.
Rajan
Salut @Rajan, merci pour le tuyau. Je viens de découvrir comment contentsfonctionne, donc je ne voulais pas y mettre d'informations basées sur de fausses hypothèses ... J'ai ajouté l'explication telle que je la comprends, mais si quelqu'un remarque qu'il y a une erreur, n'hésitez pas à le signaler ^ ^. J'ai également ajouté un lien pour que les gens puissent enquêter plus avant ... Une chose que j'ai remarquée, alors que cela dit que cela ne fonctionne pas sur IE11, je l'ai essayé sur IE 11.657.18362.0 et cela a bien fonctionné (mais, puisque je suis en utilisant angular, il pourrait y avoir un polyfill quelque part, donc je ne le garantirais pas à 100% sur d'autres environnements)
Ruben Negredo
Très bonne réponse. OMI cela devrait être accepté.
adamsfamily
-3

essaye ça

@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
la source