Diferentes Maneiras de Criar Eventos no Angular
Um dos aspectos essenciais em aplicações web modernas é a interatividade, o Angular oferece várias maneiras para lidar com isso, aproveitando tanto as funcionalidades nativas do Javascript quanto as capacidades mais avançadas do framework. Neste texto, vou discutir algumas abordagens que podem ser relevantes para a interatividade de suas aplicações Angular.
Observação: Os exemplos mostrados aqui utilizam Signal Queries para a captura dos elementos no template.
addEventListener (JavaScript Nativo)
Vamos começar com o addEventListener nativo do Javascript, que é a abordagem mais simples e direta para adicionar eventos em elementos. Embora o Angular forneça ferramentas mais especializadas, o addEventListener ainda é uma solução válida para quem deseja uma implementação mais simplificada.
@Component({
template: `<button #el>click</button>`,
})
export class MyComponent implements OnInit {
el = viewChild.required<ElementRef>('el');
ngOnInit(): void {
this.el().nativeElement.addEventListener('click', () => {
console.log('Clique no elemento!');
});
}
}
Event Binding (Angular)
Essa é a forma mais comum de lidar com eventos no Angular. Utilizando os parenteses ‘()’ no template para acossiar eventos template diretamente a métodos do componente, facilitando a interação entre a view e a lógica do componente.
@Component({
template: `<button (click)="onButtonClick()">click</button>`,
})
export class EventBindingComponent {
onButtonClick(): void {
console.log('Clique no elemento!');
}
}
Listen com Renderer2 (Angular)
O Renderer2 é uma API do Angular para manipulação da árvore de Document Object Model (DOM) de forma segura e em múltiplas plataformas (Web Browser ou Server-Side Rendering (SSR)). Usando o método listen do Renderer2, é possível ouvir eventos em elementos.
@Component({
template: `<button #el>click</button>`,
})
export class MyComponent implements OnInit, OnDestroy {
el = viewChild.required<ElementRef>('el');
renderer2 = inject(Renderer2);
unlistener!: () => void;
ngOnInit(): void {
this.unlistener = this.renderer2
.listen(this.el().nativeElement, 'click', () => {
console.log('Clique no elemento!');
});
}
ngOnDestroy(): void {
this.unlistener();
}
}
O Renderer2 é uma ótima opção para aplicações em plataformas não web ou SSR, além de ser útil para adicionar eventos em elementos globais como “window”, “document” e “body” para aplicações SSR, o Angular lida com a verificação desses elementos automaticamente.
HostListener (Angular)
Diferente dos outros exemplos, o HostListener é um decorator que escuta eventos no host do componente e executa a lógica de uma função toda vez que o evento é disparado. O HostListener ouve os eventos no próprio elemento que contém o componente, e não nos seus elementos filhos.
import { HostListener } from '@angular/core';
@Component({...})
export class MyComponent {
@HostListener('click')
click(): void {
console.log('Clique no host!');
}
}
O HostListener está perfeitamente integrado ao ciclo de vida dos componentes do Angular, permitindo um código menos verboso. É ideal para capturar eventos no host do componente.
Output (Angular)
A função output é utilizada para emitir eventos do componente filho para o componente pai. Essa abordagem é muito útil para a comunicação entre componentes.
import { Component, output } from "@angular/core";
@Component({
selector: 'componente-filho',
standalone: true,
template: `<button (click)="buttonClick()">click</button>`,
})
export class FilhoComponent {
onButtonClick = output<string>();
buttonClick(): void {
this.onButtonClick.emit('click');
}
}
@Component({
selector: 'componente-pai',
standalone: true,
imports: [FilhoComponent],
template: `<componente-filho (onButtonClick)="onChildButtonClick($event)" />`,
styles: ``
})
export class PaiComponent {
onChildButtonClick($event: string): void {
console.log('Clique no elemento do componente filho!', $event);
}
}
fromEvent (RxJs)
O fromEvent do RxJs é uma maneira reativa e assíncrona de criar eventos, transformando-os em Observables. Essa abordagem facilita a composição e manipulação de eventos, permitindo o uso dos operators do RxJs.
import { fromEvent } from 'rxjs';
@Component({
template: `<button #el>click</button>`,
})
export class MyComponent implements OnInit, OnDestroy {
el = viewChild.required<ElementRef>('el');
subscription = Subscription.EMPTY;
ngOnInit(): void {
const evento = fromEvent(this.el().nativeElement, 'click');
this.subscription.add(
evento.subscribe(() => {
console.log('Clique no elemento!');
})
);
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
}
Essa abordagem é extremamente poderosa para cenários de reatividade, pois você tem controle total sobre os fluxos de eventos, podendo utilizar operadores como take, delay, entre outros. Veja um exemplo simples:
fromEvent(window, 'click')
.pipe(take(1), delay(1000))
.subscribe(() => {
console.log('Clique na janela!');
});
Nesse exemplo, o evento de click acontece apenas uma vez e leva 1 segundo para ser disparado.
Conclusão
O Angular oferece diversas maneiras de lidar com eventos, permitindo flexibilidade conforme as necessidades da aplicação. O uso de addEventListener é mais direto e familiar para quem vem do Javascript. O fromEvent traz os benefícios da programação reativa, ideal para cenários complexos e assíncronos. O Renderer2 oferece compatibilidade com múltiplas plataformas, ideal para aplicações SSR.
A escolha da abordagem correta depende dos requisitos específicos da aplicação, como a necessidade de manipulação de eventos em várias plataformas ou o uso de programação reativa.
Informações Adicionais
Quero deixar claro que não sou especialista no assunto. Se cometi algum erro ou passei informações incorretas, fique à vontade para corrigir. Também estou aberto a sugestões de melhoria ou qualquer feedback que me ajude a melhorar.