Múltiples contenidos ng

95

Estoy tratando de construir un componente personalizado usando múltiples ng-contenten Angular 6, pero esto no funciona y no tengo idea de por qué.

Este es mi código de componente:

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

Estoy tratando de utilizar este componente en otro lugar y hacer dos dentro de código HTML diferente bodyy el encabezado selectde ng-content, algo como esto:

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

Pero el componente se está quedando en blanco.

¿Saben lo que podría estar haciendo mal o cuál es la mejor manera de renderizar dos secciones diferentes en el mismo componente?

¡Gracias!

Lucas Santos
fuente
Lo siento, stackoverflow no guardó mi segundo fragmento de código: el código que estoy usando en el componente es algo como esto: <div #header> Este es el contenido del encabezado </div> <div #body> Este es el contenido del cuerpo </div>
Lucas Santos

Respuestas:

179
  1. Puede agregar atributos ficticios headery bodyen lugar de referencias de plantilla (#header, #body).
  2. Y transcluir usando ng-contentcon selectatributo like 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>

MANIFESTACIÓN

Amit Chigadani
fuente
6
Si no desea renderizar div adicional o cualquier otra etiqueta, debe usar <ng-container>
sobczi
3
@AmitChigadani Creo que @sobczi quiso decir que puedes reemplazar <div header>con <ng-container header>.
user12893298320392
3
Confirmo la sustitución <div header>con <ng-container header>obras también.
azerafati
49

Para ajustarse a las especificaciones del componente web . Incluso si eso es Angular. Se trata de evitar atributos para el selector como directivas angulares o atributos reservados con otro uso. Entonces, solo usamos el atributo "ranura". Veremos <ng-content select="[slot=foobar]">como <slot name="foobar">.

Ejemplo:

hello-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>

Resultado

This is a Hello World example.

Ejemplo de Stackblitz

Puede utilizar el nombre que desee, como "plátano" o "pescado". Pero "inicio" y "fin" son una buena convención para colocar elementos antes y después.

Dominik
fuente
¿Cómo puedo consultar esos elementos? con ranura de nombre.
Nexeuz
Depende de su configuración angular y de componentes y de lo que desee exactamente. Puede utilizar ViewChild en TS o :hosty ::ng-deepen SCSS. Pero este es solo un ejemplo. Consulte Stackblitz Quizás ::slotted/ ::contenttambién funcione. Pero no estoy seguro. La web ofrecerá más información sobre este tema. Por lo general, solo debe diseñar el componente en sí. Y evite diseñar cosas fuera (global). De lo contrario, tendrá efectos secundarios no deseados.
Dominik
Una buena práctica es envolverlo. Vea el ejemplo actualizado de Stackblitz en mi último comentario. Vea el archivo html y css del componente. Debería preferir esto a ng-deep. Por ejemplo, <div class="end"><ng-content></ng-content></div>porque este elemento es accesible en el componente. El ng-content es solo un pseudo elemento que es reemplazado por el elemento acoplado afuera. Entonces tienes que usar ng-deep selector.
Dominik
9

alternativamente, puede utilizar:

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

Complementando las otras respuestas:

También puede hacerlo con etiquetas personalizadas (como <ion-card>, <ion-card-header>y <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>

Recibirá un mensaje de advertencia, pero funcionará. Puede suprimir los mensajes de advertencia o utilizar etiquetas conocidas como headero footer. Sin embargo, si no le gusta ninguno de estos métodos, debería optar por una de las otras soluciones.

Wesley Gonçalves
fuente