JavaScript de Cero a Experto / Eventos y listeners
Delegación de eventos: un listener para toda la lista
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.