Mehrere ng-Inhalte

95

Ich versuche, eine benutzerdefinierte Komponente mit mehreren ng-contentin Angular 6 zu erstellen , aber dies funktioniert nicht und ich habe keine Ahnung warum.

Dies ist mein Komponentencode:

<div class="header-css-class">
    <ng-content select="#header"></ng-content>
</div>
<div class="body-css-class">
    <ng-content select="#body"></ng-content>
</div>

Ich versuche, diese Komponente an einer anderen Stelle zu verwenden und zwei verschiedene HTML-Codes innerhalb bodyund in der Kopfzeile selectvon zu rendern ng-content:

<div #header>This should be rendered in header selection of ng-content</div>
<div #body>This should be rendered in body selection of ng-content</div>

Die Komponente wird jedoch leer.

Weißt du, was ich falsch machen könnte oder wie ich zwei verschiedene Abschnitte in derselben Komponente am besten rendern kann?

Vielen Dank!

Lucas Santos
quelle
Leider hat stackoverflow mein zweites Code-Snippet nicht gespeichert: Der Code, den ich in der Komponente verwende, sieht ungefähr so ​​aus: <div #header> Dies ist der Header-Inhalt </ div> <div #body> Dies ist der Body-Inhalt </ div>
Lucas Santos

Antworten:

180
  1. Sie können Dummy-Attribute headerund bodyim Gegensatz zu Vorlagenreferenzen hinzufügen (#header, #body).
  2. Und transclude mit ng-contentmit selectAttribut wie select="[header]".

app.comp.html

<app-child>
    <div header >This should be rendered in header selection of ng-content</div>
    <div body >This should be rendered in body selection of ng-content</div>
</app-child>

child.comp.html

<div class="header-css-class">
    <ng-content select="[header]"></ng-content>
</div>
<div class="body-css-class">
    <ng-content select="[body]"></ng-content>
</div>

DEMO

Amit Chigadani
quelle
6
Wenn Sie kein zusätzliches div oder ein anderes Tag rendern möchten, sollten Sie <ng-container>
sobczi
3
@AmitChigadani Ich glaube @sobczi gemeint , dass Sie ersetzen <div header>mit <ng-container header>.
user12893298320392
3
Ich bestätige auch das Ersetzen <div header>durch <ng-container header>Werke.
Azerafati
49

Anpassen der Webkomponenten- Spezifikationen. Auch wenn das Angular ist. Es geht darum, Attribute für Selektoren wie Angular-Direktiven oder reservierte Attribute mit einer anderen Verwendung zu vermeiden. Wir verwenden also einfach das Attribut "slot". Wir werden sehen <ng-content select="[slot=foobar]">als <slot name="foobar">.

Beispiel:

hallo-world.component.html

<ng-content select="[slot=start]"></ng-content>
<span>Hello World</span>
<ng-content select="[slot=end]"></ng-content>

app.component.html

<app-hello-world>
  <span slot="start">This is a </span>
  <span slot="end"> example.</span>
</app-hello-world>

Ergebnis

This is a Hello World example.

Stackblitz Beispiel

Sie können einen beliebigen Namen wie "Banane" oder "Fisch" verwenden. Aber "Start" und "Ende" sind eine gute Konvention, um Elemente davor und danach zu platzieren.

Dominik
quelle
Wie kann ich diese Elemente abfragen? mit Namensschlitz.
Nexeuz
Dies hängt von Ihren Winkel- und Komponenteneinstellungen ab und davon, was Sie genau möchten. Sie können ViewChild in TS oder :hostund ::ng-deepin SCSS verwenden. Dies ist jedoch nur ein Beispiel. Siehe Stackblitz Vielleicht ::slotted/ ::contentwird auch funktionieren. Aber nicht sicher. Das Web bietet mehr zu diesem Thema. Im Allgemeinen sollten Sie nur die Komponente selbst formatieren. Und vermeiden Sie es, Dinge außerhalb (global) zu stylen. Andernfalls treten unerwünschte Nebenwirkungen auf.
Dominik
Eine gute Praxis ist es, es einzuwickeln. Siehe das aktualisierte Stackblitz-Beispiel in meinem letzten Kommentar. Siehe die HTML- und CSS-Datei der Komponente. Sie sollten dies ng-deep vorziehen. ZB <div class="end"><ng-content></ng-content></div>Weil auf dieses Element in der Komponente zugegriffen werden kann. Der ng-Inhalt ist nur ein Pseudoelement, das durch das angedockte Element außerhalb ersetzt wird. Sie müssen also den ng-deep-Selektor verwenden.
Dominik
9

alternativ können Sie verwenden:

app.comp.html

<app-child>
    <div role="header">This should be rendered in header selection of ng-content</div>
    <div role="body">This should be rendered in body selection of ng-content</div>
</app-child>

child.comp.html

<div class="header-css-class">
    <ng-content select="div[role=header]"></ng-content>
</div>
<div class="body-css-class">
    <ng-content select="div[role=body]"></ng-content>
</div>
Angelo Radici
quelle
4

Ergänzung der anderen Antworten:

Sie können es auch tun , mit benutzerdefinierten Tags (wie <ion-card>, <ion-card-header>, und <ion-card-content>).

app.comp.html

<app-child>
    <app-child-header>This should be rendered in header selection of ng-content</app-child-header>
    <app-child-content>This should be rendered in content selection of ng-content</app-child-content>
</app-child>

child.comp.html

<div class="header-css-class">
    <ng-content select="app-child-header"></ng-content>
</div>
<div class="content-css-class">
    <ng-content select="app-child-content"></ng-content>
</div>

Sie erhalten eine Warnmeldung, die jedoch funktioniert. Sie können die Warnmeldungen unterdrücken oder bekannte Tags wie headeroder verwenden footer. Wenn Ihnen eine dieser Methoden jedoch nicht gefällt, sollten Sie sich für eine der anderen Lösungen entscheiden.

Wesley Gonçalves
quelle