
Criando um componente Angular com conteúdo dinâmico utilizando ng-content
ng-content é um ótimo recurso para criar componentes Angular que aceitem conteúdo dinâmico em determinados locais da template.
Frameworks/libs para JavaScript como Angular, ReactJS, Vue.js e outros oferecem inúmeras praticidades durante o processo de desenvolvimento frontend, não há como negar.
Todo desenvolvedor deve ter em mente boas práticas e o reaproveitamento de código sempre que possível, uma técnica (de muitas) para concretizar este conceito é conhecida como arquitetura ou desenvolvimento voltado a uma estrutura master-detail.
Trazendo para o contexto do framework deste post (Angular 😉), master-detail ajuda a…
“Manter todos os recursos em um componente à medida que o aplicativo cresce não será passível de manutenção. Você vai querer dividir grandes componentes em subcomponentes menores, cada um focado em uma tarefa ou fluxo de trabalho específico. — Documentação do Angular
Partindo do princípio que você já conhece o decorator @Input() (uma forma de injeção de dados em um componente), vamos falar do ng-content. (Input fica para uma outra postagem, caso ainda não conheça 😎)
ng-content
Utilizado para projeção de conteúdo, permite passar qualquer conteúdo entre as tags de abertura e fechamento do componente criado. Não entendeu? Vamos lá…
Digamos que você possua um componente item (item.component.ts) com a seguinte declaração:
Template neste caso substitui o arquivo .html que você teria… Apenas para ficar mais fácil de exemplificar.
Ok. Vamos imaginar que você deseja adicionar um checkbox, radio button ou qualquer outro elemento que necessite de uma lógica acoplada ao componente pai (master). Leve em consideração que item é o componente filho (detail).
É comum seguir com a ideia de adicionar o checkbox dentro do item (detail), já que visualmente ele não se encontraria no pai (master). Dependendo da ocasião utilizar emissão de eventos ou @ContentChild() tornaria a situação ainda complexa, muitas vezes sem necessidade.
É possível adicionar o checkbox via ng-content e manipular toda sua lógica no componente pai, ele estará em um laço de repetição (*ngFor).
A posição em que encontra-se <ng-content></ng-content> será onde o elemento que você passar vai aparecer. Com elemento quero dizer, qualquer conteúdo HTML.
Adicionando checkbox
Apenas abstraindo como é possível passar qualquer conteúdo para o local em que você definiu o <ng-content> no item. Passando um input do tipo checkbox…
<item>
<input type="checkbox"/>
</item>
Pratique no Stackblitz
app.component.ts
O app.component.ts cria uma variável chamada items que é um array de objetos, neste exemplo contém title, description e checked (identifica se o checkbox está marcado ou não).
Temos um método toggle() com um forEach, ele basicamente percorre o array de objetos trocando o valor da propriedade checked, quer dizer que, se checked = true passará a ser false e vice-versa.
É no app.component que realizamos a iteração dos objetos com *ngFor e passamos o objeto para o decorator @Input() presente no item.
<item *ngFor="let item of items" [item]="item">
<input type="checkbox" [(ngModel)]="item.checked"/>
</item>
De forma rápida, ngModel realiza o bind do valor item.checked com o checkbox, isto é, muda a maneira com que ele aparece para o usuário, marcado ou não.
A maneira com que ngModel aparece, entre colchetes e parênteses [(ngModel)] é chamada de two way data binding no Angular.
item.component.ts
Perceba que item.component.ts recebe do app.component.ts um array de objetos via @Input() e instancia uma variável item.
Você não só pode como deve criar uma interface para identificar o tipo que está trabalhando.
Interface para item
Se preferir criar uma interface para Item, ficaria assim:
Para utilizar a interface é simples, basta na declaração das variáveis trocar any para Item (e importar a interface).
items: Item[];
Múltiplos ng-content
Quando for utilizar mais de um ng-content em um componente você precisará informar uma propriedade select.
Veja que utilizamos <ng-content select=”[title]”></ng-content> para indicar qual será o seletor a ser utilizado quando os dados forem injetados.
Para injetar o conteúdo em cada um dos ng-content:
Utilizamos title diretiva para informar que o conteúdo Título é referente ao ng-content com select=”[title]” e Description ao ng-content com select description.
Os exemplos do artigo encontram-se no Stackblitz.
Referências
- Master-detail (definição): https://en.wikipedia.org/wiki/Master%E2%80%93detail_interface
- Master-detail (Documentação Angular): https://angular.io/tutorial/toh-pt3
- ngModel (Documentação Angular): https://angular.io/api/forms/NgModel#description
Conheça o blog Dev Senior: fórum, guias para integrações, documentações de APIs e atualizações sobre os produtos da Senior. — https://dev.senior.com.br/
Buscando oportunidades?
Tiago Boeing
Dev frontend na equipe de Arquitetura, time de Tecnologia, estudante de Ciência da Computação, nos tempos vagos jornalista e joga CS GO.