Você já tentou adicionar um trecho de código HTML dentro de um componente Angular, mas o conteúdo não foi projetado como esperado? Isso pode parecer um desafio dentro do framework, principalmente quando se deseja criar componentes reutilizáveis. Felizmente, Angular oferece ferramentas poderosas para essa tarefa: ng-content
e ngTemplateOutlet
.
Antes de começar a leitura abaixo, eu gostaria que você entendesse os conceitos de ng-content, ng-template, ng-container e *ngTemplateOutlet nesse artigo da freeCodeCamp: Tudo o que você precisa saber sobre ng-template, ng-content, ng-container e *ngTemplateOutlet em Angular
O que é ng-content?
A diretiva ng-content permite a projeção de conteúdo dentro do componente, trabalhando de forma similar ao elemento HTML nativo slot
, porém com algumas funcionalidades Angular.
Em suma, Essa diretiva funciona como um espaço reservado dentro de um componente, permitindo a inserção de conteúdo externo. Isso é particularmente útil quando se desenvolvem componentes que precisam ser altamente reutilizáveis e personalizados.
Exemplo básico de uso do ng-content
Vamos considerar um exemplo simples de um componente card
que pode exibir conteúdo dinâmico:
card.component.ts
import { ChangeDetectionStrategy, Component } from '@angular/core'; @Component({ selector: 'app-card', templateUrl: './card.component.html', styleUrl: './card.component.scss', changeDetection: ChangeDetectionStrategy.OnPush }) export class CardComponent {}
card.component.html
<article class="card"> <header> <ng-content select="[title]"></ng-content> </header> <!-- body / content --> <section> <ng-content></ng-content> </section> </article>
Neste exemplo, utilizamos a diretiva ng-content de duas maneiras:
- Com o atributo select, para especificar qual parte do conteúdo projetado deve aparecer em diferentes seções do componente
- Sem o atributo select, para projeção geral do componente.
A utilização do card fica desta forma:
app.parent.html
<app-card> <!-- ng-content select title attribute --> <h2 title>Lorem Ipsum</h2> <!-- ng-content general --> <div> <p> Lorem ipsum dolor sit amet consectetur, adipisicing elit. Voluptatum fuga reprehenderit adipisci expedita repellendus dolorem non laborum fugiat, voluptatem odit nihil quae rem laudantium. Quos deserunt numquam quae totam doloribus. </p> </div> </app-card>
Com o componente card
estruturado dessa forma, temos a flexibilidade de projetar conteúdos textuais, ou conteúdos com imagens - as possibilidades são infinitas!
Mas calma aí... isso ainda é muito estático, e eu procuro uma abordagem mais dinâmica. Tem jeito? TEM! Vamos para a próxima parte do artigo.
O que é ngTemplateOutlet?
Enquanto o ng-content é ótimo para a projeção de conteúdo estático, a diretiva ngTemplateOutlet oferece uma abordagem mais dinâmica, permitindo a projeção de conteúdo em tempo de execução.
Exemplo
- Vamos adicionar uma mudança no nosso componente card, com um input de TemplateRef para podermos passar a projeção de conteúdo que queremos.
- No template HTML, vamos remover todos os ng-content, e passar um ng-container que contém a diretiva de *ngTemplateOutlet, que vai receber o TemplateRef
<article class="card"> <ng-container *ngTemplateOutlet="cardTemplateRef() ?? null"></ng-container> </article>
import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, input, TemplateRef } from '@angular/core'; @Component({ selector: 'app-card', standalone: true, imports: [CommonModule], templateUrl: './card.component.html', styleUrl: './card.component.scss', changeDetection: ChangeDetectionStrategy.OnPush }) export class CardOutletComponent { cardTemplateRef = input<TemplateRef<unknown>>(); }
Lembrando que precisamos adicionar o CommonModule para termos acesso ao *ngTemplateOutlet
E a utilização do nosso card
com TemplateRef:
<app-card [cardTemplateRef]="textTemplate"></app-card-outlet> <app-card [cardTemplateRef]="imageTemplate"></app-card-outlet> <ng-template #textTemplate> <header> <h2>Lorem Ipsum</h2> </header> <section> <div> <p> Lorem, ipsum dolor sit amet consectetur adipisicing elit. Neque, fuga officiis ex ducimus, cupiditate, id culpa ipsa eligendi maiores autem quod architecto eum veniam expedita omnis. Vitae debitis quibusdam a? </p> </div> </section> </ng-template> <ng-template #imageTemplate> <header> <h2>Lorem Ipsum</h2> </header> <section> <img src="path/to/image" alt="my alt text IS IMPORTANT MAKE SURE YOU ARE ENHANCING A11Y IN YOUR PROJECT" /> <p> Lorem ipsum, dolor sit amet consectetur adipisicing elit. Quia, tenetur recusandae? Quo minus iusto nihil explicabo assumenda recusandae magnam quia ipsum sint impedit, totam, nobis amet libero, dolorem harum cumque. </p> </section> </ng-template>
Comparação
Embora ng-content e ngTemplateOutlet sejam usados para projeção de conteúdo, eles têm diferentes casos de uso e benefícios:
- ng-content: ideal para conteúdo estático. Permite definir pontos específicos no componente para a inserção de conteúdo externo, sendo excelente para componentes de layout (como o nosso card).
- ngTemplateOutlet: Melhor para projeção de conteúdo dinâmico. Permite a inserção de templates diferentes com base em condições lógicas ou variável de referência no ng-template. Oferece maior flexibilidade e controle em tempo de execução.
Conclusão
Entender e usar ng-content e ngTemplateOutlet pode aumentar significativamente a reutilização e a flexibilidade dos seus componentes Angular.
Ao entender e dominar essas funcionalidades, você estará mais bem equipado para criar aplicações Angular altamente dinâmicas e personalizáveis.
Referências
- https://angular.dev/guide/components/content-projection
- https://www.freecodecamp.org/news/everything-you-need-to-know-about-ng-template-ng-content-ng-container-and-ngtemplateoutlet-4b7b51223691/
- https://medium.com/senior/criando-componente-angular-com-conteudo-dinamico-ng-content-82334babe134
- https://stackoverflow.com/questions/52638718/multiple-ng-content
- https://andrewrosario.medium.com/ngtemplateoutlet-o-segredo-da-personaliza%C3%A7%C3%A3o-6f3203787a56
- https://blog.angular-university.io/angular-ng-template-ng-container-ngtemplateoutlet/
- https://consolelog.com.br/customizando-componente-com-ngtemplateoutlet-angular-2/
Top comments (1)
Excelente artigo! Parabéns Brunão.