← Volver al blog
4 min de lecturaFrontend

Angular Tips | Proyección de contenido para mejorar la reutilización de componentes

Uso de ng-content y proyección para componentes más reutilizables y alineados con buenas prácticas.

La reutilización es uno de los pilares de la ingeniería de software y un indicador importante de, entre otras cosas, la calidad de la arquitectura de un módulo, componente, sistema…

Angular propone una arquitectura basada en Web Components con el objetivo de mejorar la calidad del proyecto, la reutilización de bloques de código, la modularización…

Algunas de las técnicas más conocidas para escribir componentes son la composición y la parametrización. Con ellas podemos encapsular bloques de código unos dentro de otros (dando lugar a nuevos componentes) y configurar su apariencia y comportamiento mediante parámetros.

El objetivo de este artículo es presentar una técnica menos habitual que mejora la reutilización de los componentes: la proyección.

Ejemplo de composición

list.component.html


<h1> List of items </h1>
<item *ngFor="let item of items"> </item>

item.component.html

<div>
  <h2> {{ item.title }} </h2>
  <p> {{ item.text }} </p>
</div>

Con esta técnica podemos crear componentes componiendo otros.

Ejemplo de parametrización

parameterized.component.ts

@Component({
  ...
})
export class ParametrizedComponent {
  @Input() param1: string;  
  @Input() param2: boolean;

  constructor() {}
}

parameterized.component.html

<h1> {{ param1 }} </h1>
<span *ngIf="param2" class="badge badge-secondary"> New </span>

foo.component.html

<h1> This is an example of ParameterizedComponent usage </h1>
<parametrized
  [param1]="This is a title"  
 [param2]="true">
</parameterized>

Con esta técnica creamos componentes con apariencia y comportamiento dinámicos en función de parámetros.

Mejorar la reutilización: proyección de componentes

Con las técnicas anteriores hemos encapsulado bloques en componentes, componiéndolos para crear otros (composición) y dándoles distinto comportamiento y apariencia según parámetros.

Sin embargo, podemos ir un paso más allá.

Imagina que quieres crear un layout con una jerarquía que pueda variar más allá de lo que permiten parámetros fijos:

Podríamos usar composición y parametrización, pero limitaríamos los parámetros y nos obligaríamos a escribir componentes y plantillas solo para usarse en… ¿quizá un único componente?

Veamos cómo podría ser la plantilla usando proyección para crear un componente “card” (con cabecera, cuerpo y pie):

tree.component.html

<card>
  <card-header> Some header </card-header>
  <card-body>
    <div class="content">
      <h2> Title </h2>
      <p> Lorem impsum... </p>
      <img src="awesome-foo.png">
    </div>
  </card-body>
  <card-footer> With love by @rjlopez </card-footer>
</card>

Para permitir esta jerarquía usaremos la etiqueta de Angular <ng-content>. Esta etiqueta carga en el componente la plantilla que va dentro de la etiqueta de nuestro componente.

card.component.html

<div class="card text-center">
  <ng-content select="app-card-header"> </ng-content>
  <ng-content select="app-card-body"></ng-content>
  <ng-content select="app-card-footer"></ng-content>
</div>

card-header.component.html

<div class="card-header">
  <ng-content></ng-content>
</div>

Con lo anterior, usando <ng-content>, indicamos que el componente acepta HTML anidado. ¿Qué etiqueta acepta? Mediante el atributo select le decimos que debe aceptar etiquetas de tipo <app-card-header>. Si no se pasa valor a select, aceptará todo el contenido.

Conclusiones

Con esta técnica podemos crear componentes jerárquicos y menos acoplados a otros, lo que mejora mucho la reutilización. Como resultado obtenemos una arquitectura más flexible y un mayor grado de reutilización del código.

rjlopezdev-angular-projection - StackBlitz


Publicado originalmente en dev.to.