Fue uno de esos días en los que estaba ocupado trabajando en nuevas funciones para mi proyecto de oficina. De repente, algo me llamó la atención:

Mientras inspeccionaba el DOM, vi que ngcontent
Angular lo aplicaba a los elementos. Hmm ... si contienen los elementos en el DOM final, ¿para qué sirve ? En ese momento me confundí entre
y
.
En la búsqueda por conocer las respuestas a mis preguntas descubrí el concepto de . Para mi sorpresa, también hubo
*ngTemplateOutlet
. Comencé mi viaje buscando claridad sobre dos conceptos, pero ahora tenía cuatro, ¡sonando casi igual!
¿Has estado alguna vez en esta situación? Si es así, entonces estás en el lugar correcto. Así que sin más preámbulos, analicémoslos uno por uno.
1.
Como su nombre indica el es un elemento de plantilla que utiliza angular con las directrices estructurales (
*ngIf
, *ngFor
, [ngSwitch]
y directivas personalizadas).
Estos elementos de plantilla solo funcionan en presencia de directivas estructurales . Angular envuelve el elemento del host (al que se aplica la directiva) dentroy consume el
DOM terminado reemplazándolo con comentarios de diagnóstico.
Considere un ejemplo simple de *ngIf
:

Arriba se muestra la interpretación angular de *ngIf
. Angular coloca el elemento de host al que se aplica la directiva dentro y mantiene el host como está. El DOM final es similar al que hemos visto al comienzo de este artículo:

Uso:
Hemos visto cómo se usa Angular, pero ¿y si queremos usarlo? Como estos elementos solo funcionan con una directiva estructural, podemos escribir como:

Aquí se home
muestra una boolean
propiedad del componente establecido en true
valor. La salida del código anterior en DOM:

¡No se renderizó nada! :(
Pero, ¿por qué no podemos ver nuestro mensaje incluso después de usarlo correctamente con una directiva estructural?
Este era el resultado esperado. Como ya hemos comentado, Angular reemplaza el con comentarios de diagnóstico. Sin duda, el código anterior no generaría ningún error, ya que Angular se adapta perfectamente a su caso de uso. Nunca llegarías a saber qué sucedió exactamente detrás de escena.
Comparemos los dos DOM anteriores que fueron renderizados por Angular:


Si observa de cerca, hay una etiqueta de comentario adicional en el DOM final del Ejemplo 2 . El código que interpretó Angular fue:

Angular envolvió su host dentro de otro
y convirtió no solo el externo
en comentarios de diagnóstico, ¡sino también el interno! Es por eso que no pudo ver ninguno de sus mensajes.
Para deshacerse de esto, hay dos formas de obtener el resultado deseado:

Método 1:
En este método, le proporciona a Angular el formato sin azúcar que no necesita más procesamiento. Esta vez, Angular solo se convertiría en comentarios, pero deja intacto el contenido dentro de él (ya no están dentro de ninguno
como en el caso anterior). Por lo tanto, renderizará el contenido correctamente.
Para saber más sobre cómo usar este formato con otras directivas estructurales, consulte este artículo.
Método 2:
Este es un formato bastante invisible y rara vez se usa (usando dos hermanos ). Aquí le damos una referencia a la plantilla
*ngIf
en su then
para decirle qué plantilla debe usarse si la condición es verdadera.
No se recomienda el uso de múltiples como este (podría usarlos
en su lugar) ya que no es para lo que están destinados. Se utilizan como contenedor de plantillas que se pueden reutilizar en varios lugares. Cubriremos más sobre esto en una sección posterior de este artículo.
2.
¿Alguna vez ha escrito o visto un código parecido a esto:

La razón por la que muchos de nosotros escribimos este código es la incapacidad de usar múltiples directivas estructurales en un solo elemento host en Angular. Ahora, este código funciona bien pero introduce varios vacíos adicionales en el DOM si
item.id
es un valor falso que podría no ser necesario.

Es posible que uno no se preocupe por un ejemplo simple como este, pero para una aplicación enorme que tiene un DOM complejo (para mostrar decenas de miles de datos), esto podría volverse problemático ya que los elementos pueden tener oyentes adjuntos que todavía estarán allí en el DOM escuchando eventos.
¡Lo que es aún peor es el nivel de anidación que tienes que hacer para aplicar tu estilo (CSS)!

¡No te preocupes, tenemos que ir al rescate!
El Angular es un elemento de agrupación que no interfiere con los estilos o el diseño porque Angular no lo coloca en el DOM .
Entonces, si escribimos nuestro Ejemplo 1 con :

Obtenemos el DOM final como:

Mira, nos deshicimos de esos vacíos . Deberíamos usarlo
cuando solo queremos aplicar múltiples directivas estructurales sin introducir ningún elemento adicional en nuestro DOM.
Para obtener más información, consulte los documentos. Hay otro caso de uso en el que se utiliza para inyectar una plantilla de forma dinámica en una página. Cubriré este caso de uso en la última sección de este artículo.
3.
Se utilizan para crear componentes configurables. Esto significa que los componentes se pueden configurar en función de las necesidades de su usuario. Esto se conoce como Proyección de contenido . Los componentes que se utilizan en las bibliotecas publicadas se utilizan para hacerse configurables.
Considere un componente simple :


El contenido HTML pasado dentro de las etiquetas de apertura y cierre del componente es el contenido que se proyectará. Esto es lo que llamamos Proyección de contenido . El contenido se renderizará
dentro del componente. Esto permite al consumidor del
componente pasar cualquier pie de página personalizado dentro del componente y controlar exactamente cómo quieren que se represente.
Proyecciones múltiples:
¿Qué pasaría si pudieras decidir qué contenido se debe colocar y dónde? En lugar de que todos los contenidos se proyecten dentro de un solo , también puedes controlar cómo se proyectarán los contenidos con el
select
atributo de . Se necesita un selector de elementos para decidir qué contenido proyectar dentro de un particular
.
Así es cómo:

Hemos modificado la definición para realizar la proyección de contenido múltiple. El
select
atributo selecciona el tipo de contenido que se renderizará dentro de un determinado . Aquí tenemos primero
select
que renderizar el h1
elemento de encabezado . Si el contenido proyectado no tiene ningún h1
elemento, no representará nada. De manera similar, el segundo select
busca a div
. El resto del contenido se procesa dentro del último sin
select
.
Llamar al componente se verá así:

4. * ngTemplateOutlet
… Se utilizan como contenedor de plantillas que se pueden reutilizar en varios lugares. Cubriremos más sobre esto en una sección posterior de este artículo.… Hay otro caso de uso en el que se utiliza para inyectar una plantilla de forma dinámica en una página. Cubriré este caso de uso en la última sección de este artículo.
Esta es la sección donde discutiremos los dos puntos mencionados anteriormente. *ngTemplateOutlet
se utiliza para dos escenarios: insertar una plantilla común en varias secciones de una vista independientemente de los bucles o condiciones y para hacer un componente altamente configurado.
Reutilización de plantillas:
Considere una vista en la que tenga que insertar una plantilla en varios lugares. Por ejemplo, el logotipo de una empresa que se colocará en un sitio web. Podemos lograrlo escribiendo la plantilla para el logotipo una vez y reutilizándola en todas partes dentro de la vista.
A continuación se muestra el fragmento de código:

Como puede ver, escribimos la plantilla de logotipo una vez y la usamos tres veces en la misma página con una sola línea de código.
*ngTemplateOutlet
también acepta un objeto de contexto que se puede pasar para personalizar la salida de la plantilla común. Para obtener más información sobre el objeto de contexto, consulte los documentos oficiales.
Componentes personalizables:
El segundo caso de uso *ngTemplateOutlet
son los componentes altamente personalizados. Considere nuestro ejemplo anterior de componente con algunas modificaciones:

Anterior es la versión modificada del componente que acepta tres propiedades de entrada -
headerTemplate
, bodyTemplate
, footerTemplate
. A continuación se muestra el fragmento de project-content.ts
:

Lo que estamos tratando de lograr aquí es mostrar el encabezado, el cuerpo y el pie de página tal como se recibieron del componente principal de . Si no se proporciona alguno de ellos, nuestro componente mostrará la plantilla predeterminada en su lugar. Así, creando un componente altamente personalizado.
Para utilizar nuestro componente modificado recientemente:

Así es como vamos a pasar las referencias de la plantilla a nuestro componente. Si alguno de ellos no se pasa, el componente representará la plantilla predeterminada.
ng-content frente a * ngTemplateOutlet
Ambos nos ayudan a lograr componentes altamente personalizados, pero ¿cuál elegir y cuándo?
Se puede ver claramente que *ngTemplateOutlet
nos da más poder para mostrar la plantilla predeterminada si no se proporciona ninguna.
Este no es el caso de ng-content
. Presenta el contenido como está. Como máximo, puede dividir el contenido y representarlo en diferentes ubicaciones de su vista con la ayuda de select
atributo. No puede renderizar condicionalmente el contenido dentro ng-content
. Tienes que mostrar el contenido que se recibe del padre sin medios para tomar decisiones basadas en el contenido.
Sin embargo, la elección de seleccionar entre los dos depende completamente de su caso de uso. ¡Al menos ahora tenemos una nueva arma *ngTemplateOutlet
en nuestro arsenal que brinda más control sobre el contenido además de las funciones de ng-content
!