CodeForge

JavaScript de Cero a Experto / Eventos y listeners

Delegación de eventos: un listener para toda la lista

Teoría20 min20 XP

Tu lista de gastos necesita un botón de borrar en cada item. ¿Cien items, cien listeners? ¿Y los items que se agreguen después, quién les conecta el suyo? Hoy resuelves ambos problemas con UN solo listener bien puesto: la delegación de eventos — burbujeo aplicado con inteligencia.

El problema de los elementos futuros

El módulo 7 te enseñó a crear elementos dinámicamente. Ahora conecta los cables: un li creado DESPUÉS de que corrió tu forEach de listeners… nace sordo. Nadie le conectó el suyo. Puedes acordarte de conectárselo en cada lugar donde creas items (frágil: lo olvidarás), o cambiar de estrategia por completo.

El patrón, pieza clave incluida: closest

El clic puede nacer en el botón ✕, en el texto del gasto o en el espacio vacío de la lista — y event.target será cosas distintas cada vez. Para preguntarle "¿esto fue en un botón de borrar (o dentro de uno)?" existe elemento.closest(selector): sube desde el elemento buscando el primer ancestro (o él mismo) que coincida con el selector — y devuelve null si llega arriba sin encontrarlo. El mismo idioma de selectores de siempre.

Haz la prueba completa: borra un gasto original, agrega tres nuevos, bórralos también. Ningún item recibió listener propio — la recepcionista (el listener de #lista) los atiende a todos. Fíjate en la estructura del patrón, que es siempre la misma: escuchar en el padre → closest para identificar el objetivo → if null, return (el clic no era para mí) → actuar.

¿Y por qué closest y no comparar event.target directo? Porque si el botón tuviera un icono adentro (un SVG, un span), el clic nacería EN el icono — target sería el icono, no el botón. closest sube desde donde nació hasta encontrar el .borrar, con icono o sin él. Puntería a prueba de estructuras internas.

Con delegación en la lista, tu listener hace: if (event.target.className === 'borrar') { ... }. Funciona… hasta que le pones un icono <svg> adentro al botón y deja de funcionar cuando el clic cae sobre el icono. ¿Por qué?

Mini-reto

Extiende la delegación del playground SIN agregar más listeners a la lista: dale a cada li un segundo botón .pagar (✓) que al hacerle clic marque el item con la clase pagado (defínela en el CSS: tachado y color apagado — classList.toggle para poder desmarcarlo). Pista de diseño: el mismo listener de la lista puede distinguir con dos closest — uno para .borrar, otro para .pagar. Un listener, dos acciones, items futuros incluidos.

Qué sigue

Hasta ahora reaccionas a eventos que el NAVEGADOR fabrica: clics, teclas, envíos. La próxima lección te da la fábrica: CustomEvent — eventos con tu propio nombre y tus propios datos, para que las piezas de tu app se avisen entre sí sin conocerse. La antesala de los patrones de arquitectura del módulo 13.