Quem desenvolve aplicações com Angular sabe que interatividade é chave para uma boa experiência. Clicar em botões, digitar no teclado, enviar formulários… todas essas ações precisam ser capturadas pela aplicação. É aí que entra o event binding Angular, a forma de “ouvir” eventos do DOM e reagir com código. Usando a sintaxe (evento) no template, você conecta interações da interface aos métodos do componente TypeScript de forma simples e poderosa.
Neste conteúdo vamos ver como lidar com eventos de clique, teclas (como o Enter) e até como componentes “conversam” entre si através de eventos personalizados. Prepare-se para impulsionar suas habilidades no ecossistema Angular com essas boas práticas de event binding.
Bora codar? 💪

Eventos de clique no Angular

Vamos começar pelo tipo de evento mais comum em interfaces: o clique de mouse (ou toques, em telas touch). No Angular, capturar cliques em um elemento é tão fácil quanto adicionar (click) no HTML do template e apontar para um método no componente. Quando o usuário clica, o Angular chama o método correspondente. Essa é a base do event binding e permite que sua aplicação reaja instantaneamente às ações de quem a utiliza.

Boas práticas de nomeação e (click)

Usar (click) nos templates Angular é direto: basta colocar algo como (click)="meuMetodo()" em um botão ou outro elemento clicável. Porém, é importante pensar em boas práticas de nomeação para os métodos que vão ser chamados. Em vez de usar nomes genéricos como onClick() ou handleClick(), prefira nomes descritivos que deixem claro o que a ação faz. Por exemplo, se o botão salva os dados de um formulário, um nome de método como salvarDados() ou enviarFormulario() é muito mais significativo do que handleClick. Assim, lendo o template fica fácil entender a intenção do código.
Nomear métodos pelo que fazem e não pelo evento em si torna seu código mais claro e semântico. Faz sentido?
Além disso, você pode passar o objeto do evento para o método caso precise de detalhes do clique. Basta incluir $event entre parênteses: (click)="meuMetodo($event)". O Angular então fornece o objeto do evento DOM, permitindo acessar propriedades como posição do mouse, qual elemento foi clicado etc., se necessário. Na maioria dos casos de clique de botão simples, não precisamos do $event, mas é bom saber que ele está disponível quando precisar.
Outro ponto ao lidar com cliques é considerar prevenir comportamentos padrão quando apropriado. Por exemplo, se você tem um link (<a>) que dispara uma ação dentro da aplicação (sem recarregar a página), provavelmente não quer que o clique navegue para uma nova URL. Nesse caso, dentro do método você pode chamar event.preventDefault() para impedir o comportamento padrão do navegador. Em Angular, retornar false no método não previne o comportamento padrão; use event.preventDefault() para impedir o default quando necessário. Assim, você garante que o clique execute somente o que você planejou, sem efeitos indesejados.

Desabilitar enquanto processa

Sabe aquele momento em que o dev clica várias vezes no mesmo botão por ansiedade, disparando múltiplas requisições? Podemos evitar esses cliques duplos acidentais desabilitando o botão enquanto uma ação está em processamento. Uma prática comum no Angular é usar property binding junto com event binding para desabilitar o elemento durante o processamento de uma tarefa.
Como funciona? Nós vinculamos o atributo [disabled] do botão a uma propriedade booleana do componente (por exemplo, processando) e atualizamos essa propriedade dentro do método acionado pelo clique. Vamos ilustrar:
login.component.html (exemplo de botão de login que fica temporariamente desativado):
<button (click)="login()" [disabled]="autenticando"> Entrar </button>
login.component.ts:
autenticando: boolean = false; login() { this.autenticando = true; // Simulação de processo de login (ex: chamada HTTP) setTimeout(() => { console.log('Usuário autenticado!'); this.autenticando = false; }, 2000); }
No código acima, o botão "Entrar" usa (click)="login()" para chamar o método de login. Ao mesmo tempo, [disabled]="autenticando" faz com que o botão fique desativado (disabled=true) quando a propriedade autenticando for true. No método login(), definimos autenticando = true assim que a ação inicia (por exemplo, antes de chamar uma API). Isso desativa o botão, evitando cliques repetidos enquanto o login está em andamento. Depois que o processo termina (simulado aqui com um setTimeout de 2 segundos), definimos autenticando = false para reabilitar o botão. Essa abordagem melhora a UX e previne possíveis bugs (como múltiplas requisições simultâneas). Legal, né?
Essa técnica pode ser aplicada em qualquer cenário de processamento assíncrono: enviar formulários, buscas em API, compras, etc. Com apenas poucas linhas, garantimos que o usuário não consiga disparar a mesma ação várias vezes por engano.
Isso é cuidar da experiência de quem usa a aplicação.

Entrada de texto e teclado

Nem só de cliques vive uma aplicação web. Eventos de teclado são igualmente importantes, seja para capturar quando o user pressiona Enter em um campo de texto ou para reagir conforme ela digita. O Angular torna isso simples também, usando (keyup) ou (keydown) e permitindo até filtrar por teclas específicas. Vamos explorar duas situações práticas: detectar a tecla Enter e implementar um debounce simples para entradas de texto.

Validações rápidas

No Angular, podemos escutar eventos de teclado com a mesma sintaxe de parênteses. Um caso bem comum é querer acionar alguma ação quando o usuário aperta Enter em um campo de input, por exemplo, enviar uma busca ou adicionar um item sem precisar clicar em um botão. Claro que poderíamos capturar (keyup) genérico e verificar dentro do método se a tecla pressionada foi Enter. Mas o Angular nos dá um atalho elegante: podemos usar (keyup.enter) no template para filtrar o evento apenas quando a tecla Enter for pressionada. Assim, nosso método só é chamado nessa condição, deixando o código do componente mais limpo.
Vamos ver um exemplo de um componente de busca simples, que aciona a busca tanto ao clicar no botão quanto ao pressionar Enter no campo de texto:
search.component.html:
<input #campoPesquisa type="text" placeholder="Digite o termo de busca" (keyup.enter)="buscar(campoPesquisa.value)" /> <button (click)="buscar(campoPesquisa.value)"> Buscar </button>
No template acima, temos um <input> com (keyup.enter)="buscar(campoPesquisa.value)". Repare que usamos uma referência de template #campoPesquisa para pegar o valor do input diretamente, passando campoPesquisa.value para o método. Dessa forma, se a pessoa apertar Enter enquanto digita, o Angular chama o método buscar(...) automaticamente. Também temos um botão "Buscar" com (click) chamando o mesmo método, oferecendo as duas opções de interação. Assim, quem usa a aplicação pode tanto clicar no botão quanto simplesmente dar Enter no campo para executar a busca.
No componente TypeScript, definimos o método buscar para realizar a ação desejada. Podemos incluir validações rápidas, como ignorar buscas vazias, ou dar um feedback imediato no console:
search.component.ts:
export class SearchComponent { resultados: string[] = []; // armazenar resultados ou termos buscados buscar(term: string) { if (!term) { console.log('Consulta vazia. Nada para buscar.'); return; } console.log(`Buscando pelo termo "${term}"...`); // Aqui poderia vir a lógica de busca, exemplo: chamada a serviço/API this.resultados.push(term); } }
No método acima, se o termo estiver vazio não fazemos nada (evitando buscar "nada"). Caso contrário, registramos no console o termo buscado e simulamos que guardamos o termo em uma lista de resultados (no caso real, você chamaria um serviço de busca ou filtraria uma lista local). O importante é que com (keyup.enter) tornamos a experiência mais fluida: quem desenvolve, entrega um campo de busca que responde rapidamente ao Enter, algo intuitivo para quem utiliza a interface.
Uma dica: (keyup.enter) é apenas um dos chamados event modifiers de teclado que o Angular suporta. Você pode, por exemplo, usar (keydown.shift.enter) se quiser detectar "Shift + Enter", ou (keyup.escape) para pegar quando Escape for pressionado, e assim por diante. Esses atalhos deixam o template mais expressivo e evitam código extra no componente apenas para filtrar teclas. Bem produtivo!

Debounce simples com setTimeout

Agora imagine outra situação: você quer reagir enquanto o usuário digita em um campo, por exemplo, para validar algo em tempo real ou fazer auto-complete de sugestões. Você poderia chamar um método a cada pressionar de tecla usando (keyup), mas isso pode ser custoso se a ação for pesada (como uma chamada API) ou simplesmente fornecer uma experiência ruim se executar em cada letra. A solução? Implementar um debounce, ou seja, esperar um pequeno intervalo de tempo desde a última tecla digitada antes de agir. Assim, evitamos execuções excessivas e damos chance do usuário terminar de digitar.
Uma forma simples de fazer isso em Angular, sem precisar de bibliotecas extras, é usar setTimeout combinado com clearTimeout dentro do método de tratamento do evento. Essencialmente, a cada tecla pressionada agendamos a ação para alguns milissegundos no futuro e cancelamos o agendamento anterior se uma nova tecla for pressionada nesse meio tempo. Vamos incrementar nosso componente de busca com essa ideia, para por exemplo exibir sugestões conforme o usuário digita, mas com um pequeno delay:
Ainda em search.component.html, podemos adicionar o evento (keyup) comum apontando para outro método, por exemplo (keyup)="aoDigitar(campoPesquisa.value)". (Lembrando que se usamos tanto (keyup.enter) quanto (keyup) no mesmo elemento, ambos irão disparar e então no método podemos ignorar se a tecla for Enter, já que o buscar() já cuida disso.)
No search.component.ts, implementamos o aoDigitar com debounce:
export class SearchComponent { buscaEmProgresso: any; // para guardar o timer do debounce aoDigitar(term: string) { clearTimeout(this.buscaEmProgresso); this.buscaEmProgresso = setTimeout(() => { console.log(`Sugestões para "${term}"...`); // Aqui poderia vir lógica de sugestão/autocomplete, usando o termo }, 300); } }
Como funciona: ao começar a digitar, aoDigitar é chamado a cada tecla. Dentro dele, usamos clearTimeout para cancelar o timer anterior (armazenado em buscaEmProgresso). Em seguida, iniciamos um novo setTimeout que após 300ms fará algo… neste caso, apenas um console.log simulando a busca de sugestões para o termo atual. Se o usuário continuar digitando antes dos 300ms, o timeout anterior é limpo e um novo começa, reiniciando a contagem. Só quando ele passar 300ms sem digitar é que o código dentro de setTimeout finalmente roda, evitando muitas chamadas desnecessárias.
Esse é um debounce manual simples, mas super útil em vários cenários, desde campos de busca até validação de formulário em tempo real. Vale mencionar que no Angular poderíamos usar abordagens reativas (por exemplo, RxJS debounceTime em um formulário), mas usar setTimeout é uma maneira didática e funcional de entender o conceito sem adicionar muita complexidade. O importante é garantir uma boa experiência: reagir rapidamente, mas não instantaneamente a cada tecla, para não sobrecarregar quem está usando nem o sistema.
Faz sentido? Perceba como combinamos event binding (keyup) com lógica de temporização para atingir um resultado suave. Essa preocupação com pequenos detalhes pode parecer um desafio prático no começo, mas é o tipo de conteúdo que diferencia uma aplicação profissional. E claro, qualquer dúvida, a comunidade está aí para ajudar! 😊

Comunicação com componentes filhos

Até agora falamos de eventos DOM nativos (clique, teclado) ligados a elementos HTML. Mas em aplicações Angular vamos além: frequentemente criamos componentes filhos para organizar a interface, e precisamos que esses componentes se comuniquem com seus componentes pais. Por exemplo, imagine um componente filho que representa um item de uma lista com um botão "remover". Quando clicado, esse botão deve informar ao componente pai para remover aquele item dos dados. Como fazer isso de forma elegante? A resposta é: @Output() e EventEmitter.
O Angular nos permite definir eventos personalizados em componentes. Um componente filho pode expor eventos que o pai escuta como se fossem eventos HTML. Internamente, o filho emite um evento usando uma instância de EventEmitter, e o componente pai se vincula a ele usando a sintaxe (meuEvento)="metodoNoPai($event)". Vamos por partes.

@Output() e EventEmitter

No componente filho, usamos o decorator @Output() do Angular para declarar uma propriedade que será um EventEmitter (importado de @angular/core). Podemos chamar essa propriedade de acordo com o contexto, por exemplo remover ou selecionado, novamente, nome é importante, deve expressar o que aconteceu. Essa propriedade remover será do tipo EventEmitter<T> onde T é o tipo de dado que queremos passar para o pai (pode ser um objeto, string, número, ou mesmo vazio <void> se só quisermos sinalizar algo).
Dentro do componente filho, quando ocorrer a ação (geralmente um clique em algo dentro dele), chamamos this.remover.emit(valor) para disparar o evento e enviar o valor para quem estiver escutando.
Vamos montar um exemplo para clarificar. Digamos que temos um componente filho que exibe o nome de uma pessoa e um botão de remover. Quando esse botão for clicado, o filho emite o nome para o pai remover da lista. No child.component.ts ficaria assim:
import { Component, Input, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-dev-item', template: `<button (click)="notificarRemocao()"> Remover {{ nome }} </button>` }) export class DevItemComponent { @Input() nome: string = ''; @Output() remove = new EventEmitter<string>(); notificarRemocao() { this.remove.emit(this.nome); } }
No código acima, @Input() nome permite ao pai passar um nome para o filho exibir (usamos no template do botão para mostrar "Remover [Nome]"). E definimos @Output() remove = new EventEmitter<string>(). Note que o nome do EventEmitter é remove, podemos tratá-lo como um evento chamado remove. Dentro do método notificarRemocao(), simplesmente fazemos this.remove.emit(this.nome), emitindo o nome atual. Poderíamos emitir um objeto mais complexo, se fosse o caso (por exemplo, um ID ou o próprio item).
Pronto, nosso componente filho agora "dispara" um evento personalizado chamado remove. Mas como o componente pai recebe isso? Vamos ver.
👉
Quer destravar comunicação entre componentes? Dá uma olhada no nosso guia prático.

Passando dados do filho para o pai

No componente pai, utilizamos o componente filho em seu template e nos inscrevemos no evento dele com a sintaxe de event binding já conhecida. Ou seja, no template do pai teremos algo como: <app-dev-item (remove)="removerDev($event)" [nome]="dev">. Assim, quando o filho emitir o evento remove, o Angular chama o método removerDev($event) no pai. O $event nesse caso carrega o valor emitido no EventEmitter do filho… no nosso exemplo, será a string com o nome de quem desenvolve.
Vamos ilustrar um pai simples que mantém uma lista de nomes e remove um deles quando o filho emite o evento:
parent.component.html:
<ul> <li *ngFor="let dev of devs"> <app-dev-item [nome]="dev" (remove)="removerDev($event)"></app-dev-item> </li> </ul>
parent.component.ts (parte relevante):
export class ParentComponent { devs: string[] = ['Mayk', 'Diego', 'Rodrigo', 'Laís', 'Fernanda']; removerDev(nome: string) { this.devs = this.devs.filter(d => d !== nome); console.log(`${nome} removido da lista.`); } }
No template do pai, usamos *ngFor para renderizar um <app-dev-item> para cada nome na lista devs. Passamos [nome]="dev" para cada filho e associamos (remove)="removerDev($event)". Em outras palavras, estamos fazendo binding ao evento personalizado do filho. Quando alguém clica no botão "Remover [Nome]" dentro do filho, o método notificarRemocao() do filho emite o evento, e imediatamente o Angular invoca removerDev($event) no pai, passando o nome removido. O método removerDev então atualiza a lista devs, filtrando o nome recebido, e registra no console. Simples!
Esse padrão de comunicação pai-filho é muito poderoso. Ele permite que componentes sejam mais independentes e reutilizáveis: o componente filho (DevItemComponent) não precisa saber nada sobre o pai, ele só emite eventos. O pai decide o que fazer quando recebe cada evento. Isso facilita a coesão e o reuso dos componentes na sua jornada de desenvolvimento.
Perceba que, do ponto de vista do template do pai, não há diferença sintática entre ouvir um evento nativo (como (click)) e ouvir um evento customizado do filho (remove). O Angular unificou o modelo de eventos, o que deixa a API bem consistente. Quem está começando às vezes se surpreende: "posso realmente inventar meu próprio evento assim?" – sim! 🎉 E essa comunicação aberta entre componentes vai ser importante conforme sua aplicação cresce em complexidade.

Conclusão

Você viu como o event binding no Angular permite reagir de forma declarativa e organizada às interações do usuário e eventos entre componentes. Abordamos desde o trivial (click) em um botão até capturar uma tecla Enter com (keyup.enter) , acelerando a UX com validações rápidas e implementamos um debounce simples para evitar execuções exageradas enquanto se digita. Também exploramos a comunicação entre componentes com @Output() e EventEmitter, impulsionando a arquitetura da aplicação ao permitir que componentes falem uns com os outros de forma desacoplada.
Ao dominar essas técnicas de event binding Angular, você dá um passo importante na sua jornada no ecossistema Angular. Cada clique tratado, cada tecla capturada e cada componente se comunicando corretamente significa uma aplicação mais dinâmica, robusta e amigável para quem a utiliza. E lembre-se: a comunidade Angular (e a comunidade Rocketseat) está sempre pronta para ajudar nos desafios práticos que surgirem.
No próximo conteúdo da série, vamos continuar evoluindo nossa aplicação Angular explorando o Roteamento no Angular, ou seja, como navegar entre páginas e componentes de forma single-page application.
Bora para o próximo nível? Então vamos continuar codando e aprender juntos!
Artigos_

Explore conteúdos relacionados

Descubra mais artigos que complementam seu aprendizado e expandem seu conhecimento.