Esse desafio foi muito bacana, pois sempre que precisei usar modal logo vinha na minha cabeça o material dialog, e nada contra porque eu ainda uso muito, mas construir esse componente do zero me fez entender como as coisas realmente funciona por baixo dos panos.
Publicado em 03 de maio de 2026
Esse desafio foi muito bacana, pois sempre que precisei usar modal logo vinha na minha cabeça o material dialog, e nada contra porque eu ainda uso muito, mas construir esse componente do zero me fez entender como as coisas realmente funcionam por baixo dos panos.
A primeira coisa que fiz foi criar o componente do modal, sendo:
<div class="modal-backdrop">
<section class="modal">
<button class="modal-close" type="button" (click)="close()">X</button>
<div class="header">
<ng-content select="[header]"></ng-content>
</div>
<div class="body">
<ng-content select="[body]"></ng-content>
</div>
<div class="button">
<ng-content select="[button]"></ng-content>
</div>
</section>
</div>
import { Component, HostListener, inject } from '@angular/core';
import { ModalService } from '../../services/modal-service';
@Component({
selector: 'app-modal',
templateUrl: './modal.html',
styleUrl: './modal.scss',
})
export class Modal {
private modalService = inject(ModalService);
@HostListener('document:keydown.escape')
onEscPressed() {
this.modalService.close();
}
close() {
this.modalService.close();
}
}
Notem que foi utilizado o ng-content que basicamente vai criar um slot associado ao nome dentro do select exemplo: select="[header]"
Dai no componente pai nós simplesmente criamos o conteúdo dentro do próprio componente pai, assim:
<app-modal (closed)="closeModal()">
<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>
<button button (click)="send()">Clique aqui</button>
</app-modal>
Outrro ponto é que criamos uma service para gerenciar o estado de abertura do modal
import { Injectable, signal } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class ModalService {
isOpen = signal(false);
open() {
this.isOpen.set(true);
}
close() {
this.isOpen.set(false);
}
}
com isso, a unica coisa que precisamos fazer é chamar o serviço e criar uma flag para controlar a abertura do modal
export class App {
isModalOpen = true;
modalService = inject(ModalService);
closeModal() {
this.isModalOpen = false;
}
}
e no html criamos um id usando o próprio service, além disso para testar foi criado um botão para abrir o modal
@if (modalService.isOpen()) {
<app-modal (closed)="closeModal()">
<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>
<button button (click)="send()">Clique aqui</button>
</app-modal>
}
<button type="button" (click)="modalService.open()">
Abrir modal
</button>
Esse componente foi muito bacana, pois as vezes ao usar o dialog ficamos travado em questões de estilo e comportamentos, e criando um 100% do zero, podemos customizar para o nosso caso de uso.
Carregando comentários...