Angular2-Tabellenzeilen als Komponente

99

Ich experimentiere mit angle2 2.0.0-beta.0

Ich habe eine Tabelle und der Zeileninhalt wird von angle2 folgendermaßen generiert:

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

Jetzt funktioniert dies und ich möchte den Inhalt in eine Komponente "Tabellenzeile" einkapseln.

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

In der Komponente enthält die Vorlage den Inhalt <tr> <td>.

Aber jetzt funktioniert der Tisch nicht mehr. Das heißt, der Inhalt wird nicht mehr in Spalten angezeigt. Im Browser zeigt mir der Inspektor, dass die DOM-Elemente folgendermaßen aussehen:

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

Wie kann ich das zum Laufen bringen?

fbenoit
quelle

Antworten:

110

Verwenden Sie vorhandene Tabellenelemente als Selektor

Das Tabellenelement erlaubt keine <table-line>Elemente als untergeordnete Elemente und der Browser entfernt sie nur, wenn er sie findet. Sie können es in eine Komponente einbinden und trotzdem das zulässige <tr>Tag verwenden. Einfach "tr"als Selektor verwenden.

mit <template>

<template>sollte ebenfalls erlaubt sein, funktioniert aber noch nicht in allen Browsern. Angular2 fügt <template>dem DOM eigentlich nie ein Element hinzu , sondern verarbeitet es nur intern. Daher kann dies auch in allen Browsern mit Angular2 verwendet werden.

Attributselektoren

Eine andere Möglichkeit ist die Verwendung von Attributselektoren

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

verwendet werden wie

<tr my-tr>
Günter Zöchbauer
quelle
Also würde ich meine TableItemComponent mit einem Selektor = 'tr' erstellen. Aber wie kann 'tr' an anderen Orten für andere Probleme verwendet werden?
Fbenoit
6
Wenn die übergeordnete Komponente Ihr benutzerdefiniertes trTag enthält, wird es verwendet, andernfalls findet das Standardverhalten des Browsers statt. Sie können Ihrem Komponenten-Selektor auch Attribute oder Klassen hinzufügen, z. B. <tr line-item>mit einem Komponenten-Selektor "tr[line-item] "oder <tr class="line-item">mit einem Komponenten-Selektor tr.line-item. Auf diese Weise haben Sie die volle Kontrolle. Ich habe selbst noch nichts davon in Angular2 ausprobiert, aber ich bin mir ziemlich sicher, dass dies funktioniert.
Günter Zöchbauer
5
Gibt es einen wirklichen Nachteil? Es funktioniert gut, jedoch ist die Standardeinstellungen für die tslintdirekt mich zum Style Guide empfiehlt gegen diesen. Ich mag es nicht, empfohlene Flusenregeln auszuschalten, aber soweit ich das beurteilen kann, scheint es eine ziemlich willkürliche Regel zu sein, die in einigen Situationen (wie dem Problem von OP) unvermeidbar ist
Rob
1
Ich bin mir ziemlich sicher, dass es keinen Nachteil gibt, außer dass Element-Selektoren weitaus häufiger sind und daher die Standardeinstellung sein sollten. Wenn es einen gültigen Fall wie Tabellenelemente <li>oder ähnliches gibt, sehe ich keinen Grund, warum ich ihn nicht verwenden sollte.
Günter Zöchbauer
2
Die Verwendung meines Komponenten-Selektors mit tr [Werbebuchung] hat funktioniert und entspricht der Angular Style Guide-Regel STYLE 05-03, gegen die sich tslint beschwert.
CM
30

Ich fand das Beispiel sehr nützlich, aber es funktionierte im 2.2.3-Build nicht. Nach langem Kopfkratzen funktionierte es mit ein paar kleinen Änderungen wieder.

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
quelle
1
Gute Antwort. Ich musste nur das hinzufügen MyTrComponentzum app.module.tsund funktioniert gut.
Tito Leiva
26

Hier ist ein Beispiel für die Verwendung einer Komponente mit einem Attributselektor:

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

Ausgabe:

1   2   3
11  12  13

Natürlich wäre die Vorlage in der MyTrComponent komplizierter, aber Sie haben die Idee.

Alter (Beta.0) Plunker .

Mark Rajcok
quelle
Ist es möglich, ng-Komponenten ohne Root-Tag zu rendern? So etwas wie <! - / ko -> in Knockout.js.
Ssss
@ PashaPasha, siehe stackoverflow.com/questions/34280475/…
Mark Rajcok
14
Dies funktioniert überhaupt nicht (versucht mit Winkel 2.3). Fehler geworfen:Error: Uncaught (in promise): Error: Template parse errors: Can't bind to 'myTr' since it isn't a known property of 'tr'.
Vukasin
Damit es funktioniert, müssen Sie [] in Selector hinzufügen. Vergiss das nicht.
AFetter
6

Das Hinzufügen von 'display: content' zum Komponentenstil hat für mich funktioniert.

CSS:

.table-line {
    display: contents;
}

HTML:

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

Warum funktioniert das?

Wenn Sie eine Komponente instanziieren, wird der Inhalt der Komponente wie im Winkel (nach dem Kompilieren) wie folgt in das DOM eingeschlossen:

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

Damit die Tabelle jedoch ordnungsgemäß angezeigt wird, können die trTags von nichts umbrochen werden.

Also fügen wir display: contentsdiesem neuen Element hinzu. Soweit ich weiß, bedeutet dies, dem Explorer mitzuteilen, dass dieses Tag nicht gerendert werden soll, und den inneren Inhalt so anzuzeigen, als ob kein Umbruch stattgefunden hätte. Während das Tag noch vorhanden ist, wirkt es sich nicht visuell auf die Tabelle aus, und die trTags werden so behandelt, als wären sie direkte untergeordnete Elemente destable Elemente Tags.

Wenn Sie weitere Informationen zur Funktionsweise von Inhalten benötigen: https://bitsofco.de/how-display-contents-works/

Ruben Negredo
quelle
1
Wenn möglich, bemühen Sie sich, zusätzliche Erklärungen anstelle von nur Code bereitzustellen. Solche Antworten sind in der Regel nützlicher, da sie Mitgliedern der Community und insbesondere neuen Entwicklern helfen, die Gründe für die Lösung besser zu verstehen, und dazu beitragen können, dass keine weiteren Fragen beantwortet werden müssen.
Rajan
Hallo @Rajan, danke für den Tipp. Ich habe gerade herausgefunden, wie es contentsfunktioniert, deshalb wollte ich keine Informationen auf der Grundlage falscher Annahmen veröffentlichen ... Ich habe die Erklärung so hinzugefügt, wie ich sie verstehe, aber wenn jemand bemerkt, dass ein Fehler vorliegt, können Sie ihn gerne darauf hinweisen ^ ^. Ich habe auch einen Link hinzugefügt, damit die Leute weitere Nachforschungen anstellen können ... Eine Sache, die mir aufgefallen ist, obwohl es heißt, dass dies unter IE11 nicht funktioniert, habe ich unter IE 11.657.18362.0 ausprobiert und es hat gut funktioniert (aber da ich es bin Bei Verwendung von Angular könnte es irgendwo eine Polyfüllung geben, daher würde ich dies in anderen Umgebungen nicht zu 100% garantieren.)
Ruben Negredo
Sehr gute Antwort. IMO sollte dies akzeptiert werden.
Adams Familie
-3

Versuche dies

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