Skip to content

🖱️ Clase 5 — Eventos en Angular

📅 2026-07-18 · 🗂️ Proyecto: AppClase04 (destino en este repo: app-semana04) · 🎯 Event Binding y categorías de eventos

⬅️ Viene después de Clase 4 (mismo día de clase, tema distinto: ahí es el ciclo de vida del componente, aquí son los eventos del DOM).

El profe compartió teoría sobre las categorías de eventos en Angular, y se practicó Event Binding capturando datos reales de un <input>.

🗂️ Temas de esta clase

  1. Teoría del profe: las 3 categorías de eventos en Angular (DOM, personalizados, ciclo de vida).
  2. Ejercicio envio: Event Binding con (click).
  3. Ejercicio informacion: capturar el valor de un <input> con (input) y $event.

📚 Teoría: categorías de eventos en Angular

Resumen de lo que compartió el profe (ya está también en 00-Notas/02-Conceptos.md, sección Categorías de eventos en Angular, para no duplicar el contenido).

Todo Event Binding usa la misma sintaxis, (evento)="metodo()", pero los eventos se agrupan en 3 categorías según de dónde vienen:

CategoríaDe dónde vieneEjemplo
Eventos del DOM (nativos)El navegador (clics, teclado, formularios)(click), (input), (keyup.enter)
Eventos personalizadosOtro componente (comunicación hijo → padre)@Output() cambio = new EventEmitter()
Eventos del ciclo de vidaEl propio AngularngOnInit(), ngOnChanges(), ngOnDestroy() → ver ciclo-de-vida.md

Dentro de Eventos del DOM, los más comunes:

GrupoEventosEjemplo
Ratón(click), (dblclick), (mouseenter), (mouseleave), (mousemove)<button (click)="saltar()">
Teclado(keydown), (keyup), (keypress) — se pueden filtrar por tecla(keyup.enter)="guardar()"
Formularios/Inputs(input), (change), (blur), (focus) — el envío usa (ngSubmit)(ngSubmit)="procesarFormulario()"

📌 Faltan por ver con detalle: Eventos personalizados (@Output()/EventEmitter) y el detalle completo de los del ciclo de vida (ya cubiertos en ciclo-de-vida.md).

🏋️ Ejercicio: envio (Event Binding con (click))

📝 Este componente lo armé por mi cuenta como práctica, aparte de lo que mostró el profe con saludo/bienvenida.

ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-envio',
  imports: [],
  templateUrl: './envio.html',
  styleUrl: './envio.css',
})
export class Envio {

  saludo = '';

  saludar() {
    this.saludo = '¡Hola! Gracias por escribir.';
  }

}
html
<button (click)="saludar()"> Enviar</button>
<p>{{ saludo }}</p>
  • (click)="saludar()" — Event Binding: al hacer clic en el botón, se llama al método saludar() de la clase.
  • saludar() le pone un valor a saludo (que arranca vacío ''), y como saludo se muestra con interpolación ({{ saludo }}), el texto aparece en pantalla recién después del clic — no antes.

⚠️ Errores que salieron armando esto:

  • <p>{[saludo]}</p> — mezcla mal dos sintaxis (interpolación {{ }} y property binding [ ]). Angular no reconoce {[ ]}, y tira NG5002: Unexpected character "EOF" (el parser del template se pierde). Se corrige usando doble llave: {{ saludo }}.
  • Al principio ni saludo ni saludar() existían en la clase Envio (estaba vacía, export class Envio {}) — el HTML ya los usaba, pero la clase no los tenía definidos todavía.

🏋️ Ejercicio: informacion (capturar el valor de un <input> con $event)

Segundo ejemplo del profe, con el evento nativo (input) — captura lo que el usuario va escribiendo, tecla por tecla, usando el objeto $event del DOM:

ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-informacion',
  imports: [],
  templateUrl: './informacion.html',
  styleUrl: './informacion.css',
})
export class Informacion {

  texto = '';

  escribir(evento: Event): void {
    const input = evento.target as HTMLInputElement;
    this.texto = input.value;
  }

}
html
<input (input)="escribir($event)" placeholder="Escribe tu apellido" />
<p>Escribiste : {{ texto }}</p>
  • (input)="escribir($event)" — se dispara en cada tecla que se escribe (a diferencia de (change), que solo dispara cuando el input pierde el foco).
  • $event es el objeto nativo del evento del DOM; se lo pasamos entero al método.
  • evento.target as HTMLInputElementevento.target es de tipo genérico (EventTarget), así que TypeScript no sabe que tiene .value. El as HTMLInputElement es un cast: le dice a TypeScript "confía en mí, esto es un input", para poder leer .value.

⚠️ Errores que salieron armando esto: la clase Informacion estaba vacía (export class Informacion {}) y el HTML ya llamaba a escribi($event) (con typo, sin la "r" final) — daba Property 'escribi' does not exist on type 'Informacion'. Se corrigió el nombre del método y se agregó texto/escribir() a la clase.

▶️ Cómo correrlo

Mismo proyecto que ciclo-de-vida.md, ya armado en este repo:

zsh · app-semana04
$ cd 02-Ejercicios/app-semana04
$ npm install     // solo la primera vez
$ npm start       // = ng serve → http://localhost:4200/

envio e informacion ya están cableados en app.html junto con saludo/bienvenida.

🏋️ Ejercicios con solución

Ejercicio 1 — Contador de clics

Armar un componente con un botón y un contador que empieza en 0. Cada clic en el botón debe sumar 1 al contador y mostrarlo en pantalla con interpolación. Mismo patrón que envio, pero en vez de poner un texto fijo, hay que incrementar un número.

Ver solución
ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-contador',
  imports: [],
  templateUrl: './contador.html',
  styleUrl: './contador.css',
})
export class Contador {

  clics = 0;

  contar() {
    this.clics++;
  }

}
html
<button (click)="contar()">Clic aquí</button>
<p>Clics: {{ clics }}</p>

Ejercicio 2 — Capturar el valor de un <select> con (change)

Armar un componente con un <select> de 2-3 opciones (por ejemplo, colores o ciudades). Cada vez que el usuario cambia la opción elegida, se debe guardar el valor seleccionado y mostrarlo con interpolación. Mismo patrón que informacion (usar $event, leer .value y castear), pero con el evento (change) en vez de (input), y sobre un <select> en vez de un <input>.

Ver solución
ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-color-favorito',
  imports: [],
  templateUrl: './color-favorito.html',
  styleUrl: './color-favorito.css',
})
export class ColorFavorito {

  color = '';

  seleccionar(evento: Event): void {
    const select = evento.target as HTMLSelectElement;
    this.color = select.value;
  }

}
html
<select (change)="seleccionar($event)">
  <option value="rojo">Rojo</option>
  <option value="verde">Verde</option>
  <option value="azul">Azul</option>
</select>
<p>Color elegido: {{ color }}</p>

💡 El cast cambia de HTMLInputElement a HTMLSelectElement porque evento.target ahora es el <select>, no un <input> — mismo truco, distinto tipo de elemento del DOM.

❓ Preguntas y respuestas

1. ¿Diferencia entre (input) y (change)?

(input) se dispara en cada tecla que se escribe (o cada cambio inmediato, como mover un slider). (change) se dispara una sola vez, cuando el elemento pierde el foco (o, en un <select>, al confirmar la opción elegida).

2. ¿Para qué sirve $event y por qué a veces hace falta un cast como as HTMLInputElement?

$event es el objeto nativo del evento del DOM (el mismo que llega en JS puro); se lo pasamos al método para poder leer datos como el valor escrito. Su tipo genérico es Event, y evento.target es de tipo EventTarget — muy genérico, sin propiedad .value. El cast (as HTMLInputElement, as HTMLSelectElement, etc.) le dice a TypeScript el tipo real del elemento para poder acceder a .value sin error de compilación.

3. Según la tabla de categorías de eventos de esta clase, ¿en qué categoría cae (click) y en cuál @Output()?

(click) es un evento del DOM (nativo) — viene del navegador. @Output() con EventEmitter es un evento personalizado — lo define el propio componente para comunicarse de hijo a padre. Son categorías distintas aunque ambas usen la misma sintaxis (evento)="metodo()" en el binding.

📎 Apuntes relacionados

  • ciclo-de-vida.md — primera parte de esta clase (hooks del ciclo de vida).
  • 02-Conceptos.md (sección Data BindingCategorías de eventos en Angular) — la teoría completa, con más detalle del objeto $event.

➡️ Siguiente

Ver Eventos personalizados (@Output()/EventEmitter, comunicación hijo → padre), que quedó pendiente de la teoría del profe.