Event delegation
Clase 19 de 29 • Curso de Manipulación del DOM
Contenido del curso
Clase 19 de 29 • Curso de Manipulación del DOM
Contenido del curso
Carlos Eduardo Gomez García
Jonathan 🦑 Alvarez
Jimmy Buriticá Londoño
Fernando Quinteros Gutierrez
Giselle Desiree Boyer Jimenez
Andrés Felipe Lopez gomez
Luis Alejandro Vera Hernandez
Stanley Melgar
Andres Felipe Pinchao Ramirez
Anfernee Valera
Jose David Villalobos Rodriguez
Joel Eduardo Sánchez Herrera
Alvaro Ibáñez
Usuario anónimo
Alejandro Dotor
Jonathan 🦑 Alvarez
Alejandro Dotor
Andrés Castellanos
CHRISTIAN OLIVER SOLANO NUÑEZ
Cristian Contreras
Rodrigo Andre Gutierrez
Jonathan Forero
Luciano Madroñal correa
Alejandro Forero Vanegas
Jonathan Forero
Sebastian Rodriguez
Usuario anónimo
Facundo Martinez
Jose Manuel Montaño Saenz
Camilo Perilla
Erlyn David Ascarate Lachi
Daniel David Mármol Rivero
Fernando Quinteros Gutierrez
Jonathan 🦑 Alvarez
La delegación de eventos es básicamente un contenedor padre que le pasa el evento a todos sus hijos (en realidad no se los está pasando, sino que el contenedor padre sigue estando presente en todos los hijos, es por eso que cuando clicamos a un hijo el evento es disárado). . Entendiendo esto, cuando obtenemos el target podemos saber cuál elemento hijo del padre fue clicado, por tanto, con una simple condicional puede ver si el elemento clicado es el que yo quiero. . Ojo: Eso no significa que el evento se quite de los demás elementos hijos, si tu clicas cualquier otro elemento hijo el evento se va a disparar sí o sí, pero lo que sucede es que la condición del tarjet no se cumple, por eso no hace nada. . Y sabiendo esto, puedes hacer cosas chulas como crear funciones que escuchen eventos dinámicamente, una característica de los eventos es que solo se le aplican a los elementos que están desde el inicio, pero si tu agregas otro nodo desde JavaScript los eventos no se van a escuchar para ese nuevo nodo. Entonces, una técnica que se suele usar es escuchar al padre (o en ocasiones a todo el document) y cada vez que el evento ocurra buscar a todos sus hijos que coincidan con el selector al que queremos aplicarle el evento, de esta forma no importa si los nodos se añaden posteriormente desde JavaScript, el evento será escuchado pues JavaScript directamente irá a buscar todos los nodos hijos que cumplan con dicho selector, por ejemplo: HTML
<div id="divPadre"> <div class="div"> Hola </div> </div>
JavaScript
document.querySelector(".div").addEventListener("click", () => { // Hace algo })
En este caso, si al div padre yo le añadiera desde JavaScript otro elemento con la clase div, el evento NO funcionaría:
const nuevoDiv = document.createElement("div"); nuevoDiv.className = "div"; nuevoDiv.textContent = "Nuevo div" divPadre.append(nuevoDiv)
Sin emabrgo, al usar la delegación de eventos, puedo escuchar al padre y buscar al hijo que me interesa:
nuevoDiv.addEventListener("click", event => { if(event.target.classList.contains("div")) { // Código } })
De esta forma, no importa cuantos elementos nuevos agregues al padre desde JavaScript, esto siempre va a funcionar. . Ahora, si quieres hacer algo más pro, puedes crear una función en el cual tu le pases un selector en específico para usar dentro del div, así solo tienes que llamar a esa función y pasarle el selector de tal manera que se quede escuchando por cualquier elemento nuevo que sea agregado, algo así:
eventAll("click", parentElement, elementToListen, () => { // Has algo })
Una función de ese tipo sería muy útil, porque así puedo mantener escuchando cada elemento, no importa que se agregue después con JavaScript, y sí, yo ya la cree, de hecho hice una mini librería para escuchar eventos partiendo de esta base, pueden indagar el código aquí: .
.
Claro, este código está desactualizado porque tiene un pequeño bug y hay ciertos elementos con los que no funciona, pero para eso podemos usar un MutationObserver que mire cuando el padre haya sido modificado (se le haya agregado un hijo nuevo) y a ese hijo aplicarle el evento, yo ya lo hice pero se los dejo de tarea si tienen cursiodidad sobre eso 👀
wow fan de estos resumenes!
Super 👍
📩 Event delegation
Apuntes
RESUMEN: La técnica event delegation consiste en dejar todos los eventos sucedan en un elemento superior de tal forma que este los identifique y aplique el procedimiento con condicionales
Event delegation consiste en delegar a un solo padre (el padre) el manejo/escucha de los eventos que nos interesan, de esta manera tendremos un único eventListener en lugar de tener uno por cada elemento lo cual puede impactar en el rendimiento de nuestro sitio web cuando son muchos eventListeners. Si deseamos manejar la interacción solo sobre un elemento específico dentro del nodo padre, solo se debe especificar dentro de la función, para esto se puede usar la información provista por el elemento event.
Muchas gracias
Gracias, pregunta de examen jaja
Como dato la diferencia entre target y currentTarget radica en que el primero hacer referencia al disparador del evento, donde debemos de interactuar para que este se ejecute. Por otro lado el currentTarget es el nodo padre en el que esta el disparador.
MIS APUNTES EVENT DELEGATION 😎👌
/*Utilizaremos nuestro proyecto anterior para que cuando le de click a cada uno de los elemento me salga un alert distinto */ const baseUrl = "https://platzi-avo.vercel.app"; const appNode = document.querySelector('#app'); /* 2 forma le agregaremos el escuchador de eventos al contenedor de nuestros elementos, a este patron se le conoce como delegacion de eventos estamos delegando a un solo nodo que es el padre de todos lo queremos escuchar que se encargue de manejar todos los eventos de esa zona. Es importante este patron cuando manejamos una gran cantidad de escuchadores y es manejada por la mayoria de frameworks importantates Esto hara que cuando demos click en cualquier parte del elemento se ejecute la alerta esto lo podemos arreglar Utilizando un condicional en la que utilizamos el parametro de la funcion que devuele el evento y entonces accedemos a la propiedad target a nodeName y le decimos que solo cuando el evento se hubique en el h2 dispare la alerta */ appNode.addEventListener('click', (event) => { if(event.target.nodeName === 'H2'){ window.alert("Hola"); } }); const formatPrice = price => { const newPrice = new window.Intl.NumberFormat("es-EN", { style: "currency", currency: "USD" }).format(price) return newPrice; } window .fetch(`${baseUrl}/api/avo`) .then(respuesta => respuesta.json()) .then(responseJson =>{ const todosLosItems = []; responseJson.data.forEach(item => { const imagen = document.createElement('img'); imagen.src = `${baseUrl}${item.image}`; imagen.className = "h-16 w-16 md:h-24 md:w-24 rounded-full mx-auto md:mx-0 md:mr-6" const titulo = document.createElement('h2'); titulo.className = "text-lg"; titulo.textContent = item.name; /* 1 forma de hacer que al dar click se ejecute una alerta Esto funciona pero hay que tener en cuenta que estamos agregando un eventListener por cada elemento que recibimos por parte de la API */ titulo.addEventListener('click', () => { window.alert("Hola"); }) const precio = document.createElement('div'); precio.className = "text-gray-600"; precio.textContent = formatPrice(item.price); priceAndTitle.className = "text-center md:text-left"; priceAndTitle.appendChild(titulo); priceAndTitle.appendChild(precio); const card = document.createElement("div"); card.className = "md:flex bg-white rounded-lg p-6 hover:bg-gray-300"; card.append(imagen, priceAndTitle); const container = document.createElement('div'); container.appendChild(card); todosLosItems.push(container); }); appNode.append(...todosLosItems) });
Yo estuve curioseando y encontré que además de bubling también existe Capturing.
Capturing.
Esta forma de propagación funciona al revés que bubling, va desde el elemento mas afuera, hasta el evento seleccionado, activando así todos los padres que contuviesen el mismo evento.
OJO
No confundir Capturing con está técnica enseñada en clases llamada Event delegation la segunda sigue utilizando la forma de propagación Bubling Solo que le adjunta el Escuchador de eventos al padre, para así reaccionar a todos los clicks dentro de este.
Importante destacar que los elementos dentro target.nodeName son todos en mayusculas. Si quisieras identificar un div sería "DIV" un input sería un "INPUT"
El curso esta muy padre! pero neta todo en blanco? XDD mis ojos lloran
La complejidad del ser humano crece a medida que se le brindan mas herramientas para su entorno
Les comparto este artículo
AYUDAAAAA!! Si yo quiero que el evento no sea para el H2 sino para el DIV que contiene toda la info(img, h...) Como seria el Event delegation
No se si me explico, yo quiero que cuando se haga click en cualquier parte de este contenedor (no importa si es la imagen, el titulo, o el Background ETC) sala en consola que se hizo click (claro con event delegation, no vale seleccionar el contenedor con un querySelector )
Hey hey!
Se hace de forma similar a como muestro con el H2, solo que tenemos que:
if (event.target.nodeName === 'DIV') { // ... }
DIVs hay muchos, así que debemos identificar el que queremos. Para esto sugiero agregar una clase única al momento de crear este nodo, por ejemplo: "js-card-contenedor". Y así, el condicional quedaría como:
if (event.target.nodeName === 'DIV' && event.target.classList.includes('js-card-contenedor')) { // ... }
Graciaaaaas 💚💚
¿Por qué usar event delegation? Porque cuando agregas un nodo de manera dinámica con JS este no va a poder vincularse con un eventListener. Para ello se usa un padre que se haya cargado desde un inicio. Este articulo de medium lo explican detalladamente: https://medium.com/@bretdoucette/part-4-what-is-event-delegation-in-javascript-f5c8c0de2983 . Otra razón es porque afecta el rendimiento, aquí se habla de ello: https://stackoverflow.com/questions/28627606/does-adding-too-many-event-listeners-affect-performance
evento con estilos tailwindcss
const containerCards = document.querySelector('#container'); containerCards.addEventListener('click', (event) => { if(event.target.nodeName === 'H2'){ window.alert('Activaste un evento con el texto'); } if(event.target.nodeName === 'IMG'){ window.alert('Activaste un evento con la imagen'); } }); const image = document.createElement('img'); image.src = `${URLmain}${element.image}`; image.alt = element.name; image.className = 'w-11/12 rounded-full hover:opacity-75 cursor-pointer'; const title = document.createElement('h2'); title.textContent = element.name; title.className = 'ml-2 font-medium hover:text-green-500 cursor-pointer';
Hola, comunidad. Alguien puede explicarme qué hace el método window.?
esto lo saqué de
Window Hace referencia a la ventana actual. Es el objeto principal en la jerarquía y contiene las propiedades y métodos para controlar la ventana del navegador. De él dependen todos los demás objetos de la jerarquía. Vamos a ver la lista de sus propiedades y métodos.
La variable "Window" en el contexto de los navegadores web se refiere a un objeto global que representa la ventana del navegador en la que se muestra un documento web. Es parte del modelo de objetos del navegador, que proporciona una interfaz para interactuar con los elementos de la página y realizar diversas acciones.
El objeto "Window" contiene propiedades y métodos que permiten acceder y manipular la ventana del navegador, así como interactuar con los elementos de la página web cargada en dicha ventana. Algunas de las propiedades y métodos más comunes asociados con la variable "Window" incluyen:
Document: Proporciona acceso al objeto "Document" que representa el contenido de la página web cargada en la ventana del navegador. Permite realizar manipulaciones en la estructura del documento, acceder y modificar elementos HTML, cambiar estilos, agregar eventos y más.
Location: Proporciona información sobre la URL actual de la página web cargada en la ventana del navegador y permite redireccionar a otras páginas.
Navigator: Proporciona información sobre el navegador del usuario, como el nombre, la versión y el agente de usuario. También se utiliza para detectar características y capacidades específicas del navegador.
History: Proporciona acceso y control del historial de navegación del usuario. Permite realizar acciones como retroceder o avanzar en el historial de páginas visitadas.
Alert, Confirm, Prompt: Métodos que se utilizan para mostrar cuadros de diálogo al usuario con mensajes, solicitudes de confirmación o solicitudes de entrada de texto.
Estas son solo algunas de las propiedades y métodos disponibles en el objeto "Window". La variable "Window" es esencial en la programación web, ya que permite interactuar con la ventana del navegador y crear aplicaciones web dinámicas y interactivas.
Hola, hay algún método para saber si un elemento tiene un evento asignado?
La forma que yo reviso si un elemento tiene un evento asignado lo hago a través del dev tools.
En JavaScript, no hay un método integrado para verificar si un elemento tiene un evento asignado directamente. Sin embargo, puedes utilizar algunas técnicas para determinar si se ha asignado un evento a un elemento. A continuación, te mostraré dos enfoques comunes:
Puedes verificar si un elemento tiene un evento asignado revisando la propiedad del elemento que corresponde al evento específico. Por ejemplo, si deseas verificar si se ha asignado el evento "click" a un elemento con el id "myElement", puedes hacer lo siguiente:
var element = document.getElementById('myElement'); if (typeof element.onclick === 'function') { console.log('El elemento tiene un evento click asignado.'); } else { console.log('El elemento no tiene un evento click asignado.'); }
Este enfoque comprueba directamente la existencia de un manejador de eventos en la propiedad específica del elemento. Sin embargo, este método solo funciona si el evento se ha asignado directamente a la propiedad del elemento y no a través de otros métodos como addEventListener().
getEventListeners() (solo en navegadores con compatibilidad):Algunos navegadores modernos proporcionan una función llamada getEventListeners() que puede utilizarse para obtener una lista de eventos asignados a un elemento. Sin embargo, esta función no es parte de la especificación oficial de JavaScript y puede no estar disponible en todos los navegadores.
var element = document.getElementById('myElement'); var eventListeners = getEventListeners(element); if (eventListeners.click && eventListeners.click.length > 0) { console.log('El elemento tiene un evento click asignado.'); } else { console.log('El elemento no tiene un evento click asignado.'); }
Este método utiliza la función getEventListeners() para obtener una lista de eventos y sus manejadores asociados para el elemento especificado. Luego, se verifica si hay algún manejador de eventos para el evento específico que estás buscando.
Es importante destacar que este segundo enfoque puede no funcionar en todos los navegadores, ya que no es parte de la especificación oficial. Por lo tanto, se recomienda utilizar el primer enfoque si deseas una solución más ampliamente compatible.
QUE BUENA clase, estaba construyendo una e-commerce y queria que los productos se habrieran solo al dar click en la imagen. No olviden que para usar .nodeName es en mayuzcula: "IMG", "DIV" etc, perdí media hora con eso XD
(○` u′○) ato curioso, las comparaciones del nodeName se hacen siempre en mayusculas. .
Event delegation
Al patron de la combinación de eventos y su forma del propagarse en el DOM se le llama “Event Delegation” o delegación de eventos.
Ejemplo:
// señalando a todos los P de un div.container document.querySelector("div.container").addEventListener("click", (event) => { console.log(event.target.nodeName) if (event.target.nodeName === "P") { window.alert("Hola") } })
Nota: Los “nodeName” se refieren siempre en MAYUSCULAS!
Nota2: El event delegation es un patron sumamente poderoso que debemos utilizar siempre que sea posible, especialmente cuando el numero de escuchadores de eventos sea relativamente grande o se espera que sea grande.
Esta técnica la utiliza REACT, Angular, Svelte y todos los frameworks, pues cada vez que utilizamos eventos, estos frameworks no agregan directamente a los nos sino que lo agregan al body, al document o cualquier otro elemento que se considera la raíz de la aplicación.
Muchas gracias!!
Event delegation
Es una solución eficaz para evitar el stopPropagation. Básicamente lo que debemos es colocar nuestro listener en el elemento padre y en la función a ejecutar colocamos una condicional para saber el tipo de selector que disparo el evento, ya con esta información ejecutamos código según el ejecutor del evento.
Este patrón lo debemos usar siempre que sea posible y mas cuando la cantidad de listener es relativamente enorme.
event.target siempre hará referencia al nodo que recibió el evento. Es muy posible que en este ejemplo este nodo sea un H2, IMG, o la etiqueta que muestra el precio. Para mostar la alerta cada vez que se de un click en la card sin importar que etiqueta interna recibio el click, podemos usar event.target.closest('clase de la card'). Usando la clase de la card, podemos obtener su nodo desde un node hijo.
Oh. Que genial. Me sirvio :D
appNode.addEventListener("click", (evento) => { if (evento.target.nodeName === "H2"){ window.alert('Hola'); } //De esta forma sólo funcionará para los títulos en el nodo H2 en el nodo padre document. });
De esta forma se encarga de manejar todos los elementos y que escuche solo los que requerimos, esto se usa generalmente cuando los eventos y escuchadores son realmente grandes. Todos los framewoks (Angular, Vue.js, React JS, ect) lo usan por debajo agregándolo al body, document o cualquier que ellos consideren como la raíz.
¿Si deseáramos dejar de usar un evento con esta técnica, cuál sería la mejor forma de manejarlo? me surgió la duda debido a que estamos usando condicionales
Muy buena pregunta!
Todos los eventos se deben registrar con una función:
element.addEventListener('click', miFuncion)
Así que para des-registrar se debe indicar exactamente la misma función:
element.removeEventListener('click', miFuncion)
Es por eso, que si se necesita retirar un eventListener es mala idea hacerlo con funciones anónimas (funciones que no tienen nombre) o funciones inline. Por ejemplo, esta función no hay forma de des-registrarla porque no tiene un nombre que la identifique:
element.addEventListener('click', () => console.log('holita'))