Delegación de Eventos
Delegación de Eventos
Delegación de Eventos
info/event-delegation
Comprar EPUB/PDF
ES
24 de octubre de 2022
Delegación de eventos
La captura y el propagación nos permiten implementar uno de los más poderosos patrones de manejo de
eventos llamado delegación de eventos.
La idea es que si tenemos muchos elementos manejados de manera similar podemos, en lugar de asignar
un manejador a cada uno de ellos, poner un único manejador a su ancestro común.
En el manejador obtenemos event.target para ver dónde ocurrió realmente el evento y manejarlo.
Aquí está:
Bagua Chart: Direction, Element, Color, Meaning
Northwest North Northeast
Metal Water Earth
Silver Blue Yellow
Elders Change Direction
1 de 13 24/3/24, 19:13
Delegación de eventos https://es.javascript.info/event-delegation
1 <table>
2 <tr>
3 <th colspan="3"><em>Bagua</em> Chart: Direction, Element, Color, Meaning
4 </tr>
5 <tr>
6 <td class="nw"><strong>Northwest</strong><br>Metal<br>Silver<br>Elders
7 <td class="n">...</td>
8 <td class="ne">...</td>
9 </tr>
10 <tr>...2 more lines of this kind...</tr>
11 <tr>...2 more lines of this kind...</tr>
12 </table>
En lugar de asignar un manejador onclick a cada <td> (puede haber muchos), configuramos un
manejador “atrapa-todo” en el elemento <table> .
El código:
1 let selectedTd;
2
3 table.onclick = function(event) {
4 let target = event.target; // ¿dónde fue el clic?
5
6 if (target.tagName != 'TD') return; // ¿no es un TD? No nos interesa
7
8 highlight(target); // destacarlo
9 };
10
11 function highlight(td) {
12 if (selectedTd) { // quitar cualquier celda destacada que hubiera antes
13 selectedTd.classList.remove('highlight');
14 }
15 selectedTd = td;
16 selectedTd.classList.add('highlight'); // y destacar el nuevo td
17 }
A tal código no le interesa cuántas celdas hay en la tabla. Podemos agregar y quitar <td> dinámicamente
en cualquier momento y el realzado aún funcionará.
En nuestro caso, si miramos dentro del HTML, podemos ver tags anidados dentro de <td> , como
2 de 13 24/3/24, 19:13
Delegación de eventos https://es.javascript.info/event-delegation
<strong> :
1 <td>
2 <strong>Northwest</strong>
3 ...
4 </td>
<table>
<td>
<strong> event.target
En el manejador table.onclick debemos tomar tal event.target e indagar si el clic fue dentro de
<td> o no.
1 table.onclick = function(event) {
2 let td = event.target.closest('td'); // (1)
3
4 if (!td) return; // (2)
5
6 if (!table.contains(td)) return; // (3)
7
8 highlight(td); // (4)
9 };
Explicación:
1. El método elem.closest(selector) devuelve el ancestro más cercano que coincide con el selector.
En nuestro caso buscamos <td> hacia arriba desde el elemento de origen.
2. Si event.target no ocurrió dentro de algún <td> , el llamado retorna inmediatamente pues no hay
nada que hacer.
3. En caso de tablas anidadas, event.target podría ser un <td> , pero fuera de la tabla actual.
Entonces verificamos que sea realmente un <td> de nuestra tabla.
4. Y, si es así, destacarla.
Como resultado, tenemos un código de realzado rápido y eficiente al que no le afecta la cantidad total de
3 de 13 24/3/24, 19:13
Delegación de eventos https://es.javascript.info/event-delegation
<td> en la tabla.
Digamos que queremos hacer un menú con los botones “Save”, “Load”, “Search” y así. Y hay objetos con los
métodos save , load , search … ¿Cómo asociarlos?
La primera idea podría ser asignar un controlador separado para cada botón. Pero hay una solución más
elegante. Podemos agregar un controlador para el menú completo y un atributo data-action a los
botones con el método a llamar:
El manejador lee el atributo y ejecuta el método. Puedes ver el siguiente ejemplo en funcionamiento:
4 de 13 24/3/24, 19:13
Delegación de eventos https://es.javascript.info/event-delegation
1 <div id="menu">
2 <button data-action="save">Save</button>
3 <button data-action="load">Load</button>
4 <button data-action="search">Search</button>
5 </div>
6
7 <script>
8 class Menu {
9 constructor(elem) {
10 this._elem = elem;
11 elem.onclick = this.onClick.bind(this); // (*)
12 }
13
14 save() {
15 alert('saving');
16 }
17
18 load() {
19 alert('loading');
20 }
21
22 search() {
23 alert('searching');
24 }
25
26 onClick(event) {
27 let action = event.target.dataset.action;
28 if (action) {
29 this[action]();
30 }
31 };
32 }
33
34 new Menu(menu);
35 </script>
Ten en cuenta que this.onClick está ligado a this en (*) . Esto es importante, porque de otra
manera el this que está dentro haría referencia al elemento DOM ( elem ), no al objeto Menu , y
this[action] no sería lo que necesitamos.
● No necesitamos escribir el código para asignar el manejador a cada botón. Simplemente hacer
un método y ponerlo en el markup.
● La estructura HTML es flexible, podemos agregar y quitar botones en cualquier momento.
5 de 13 24/3/24, 19:13
Delegación de eventos https://es.javascript.info/event-delegation
El patrón “comportamiento”
También podemos usar delegación de eventos para agregar “comportamiento” a los elementos de forma
declarativa, con atributos y clases especiales.
Comportamiento: Contador
Por ejemplo, aquí el atributo data-counter agrega un comportamiento: “incrementar el valor con un clic”
a los botones:
1 Counter: <input type="button" value="1" data-counter>
2 One more counter: <input type="button" value="2" data-counter>
3
4 <script>
5 document.addEventListener('click', function(event) {
6
7 if (event.target.dataset.counter != undefined) { // si el atributo exist
8 event.target.value++;
9 }
10
11 });
12 </script>
Si hacemos clic en un botón, su valor se incrementa. Lo importante aquí no son los botones sino el enfoque
general.
Puede haber tantos atributos data-counter como queramos. Podemos agregar nuevos al HTML en
cualquier momento. Usando delegación de eventos “extendimos” el HTML, agregando un atributo que
describe un nuevo comportamiento.
6 de 13 24/3/24, 19:13
Delegación de eventos https://es.javascript.info/event-delegation
En proyectos reales es normal que haya muchos manejadores en document , asignados en diferentes
partes del código.
1 <button data-toggle-id="subscribe-mail">
2 Show the subscription form
3 </button>
4
5 <form id="subscribe-mail" hidden>
6 Your mail: <input type="email">
7 </form>
8
9 <script>
10 document.addEventListener('click', function(event) {
11 let id = event.target.dataset.toggleId;
12 if (!id) return;
13
14 let elem = document.getElementById(id);
15
16 elem.hidden = !elem.hidden;
17 });
18 </script>
Veamos una vez más lo que hicimos aquí: ahora, para agregar la funcionalidad de conmutación a un
elemento, no hay necesidad de conocer JavaScript, simplemente usamos el atributo data-toggle-id .
Esto puede ser muy conveniente: no hay necesidad de escribir JavaScript para cada elemento. Simplemente
usamos el comportamiento. El manejador a nivel de documento hace el trabajo para cualquier elemento de la
página.
Resumen
7 de 13 24/3/24, 19:13
Delegación de eventos https://es.javascript.info/event-delegation
¡La delegación de eventos es verdaderamente fantástica! Es uno de los patrones más útiles entre los eventos
DOM.
A menudo es usado para manejar elementos similares, pero no solamente para eso.
El algoritmo:
Beneficios:
Tareas
Hay una lista de mensajes con botones para borrarlos [x] . Haz que funcionen.
Como esto:
8 de 13 24/3/24, 19:13
Delegación de eventos https://es.javascript.info/event-delegation
[x]
Horse
The horse is one of two extant subspecies of Equus
ferus. It is an odd-toed ungulate mammal belonging to
the taxonomic family Equidae. The horse has evolved
over the past 45 to 55 million years from a small multi-
toed creature, Eohippus, into the large, single-toed
animal of today.
[x]
Donkey
The donkey or ass (Equus africanus asinus) is a
domesticated member of the horse family, Equidae. The
wild ancestor of the donkey is the African wild ass, E.
africanus. The donkey has been used as a working
animal for at least 5000 years.
[x]
Cat
The domestic cat (Latin: Felis catus) is a small, typically
P.D. Debe haber solamente un event lintener en el contenedor, usa delegación de eventos.
solución
Abrir la solución en un entorno controlado.
Menú de árbol
importancia: 5
9 de 13 24/3/24, 19:13
Delegación de eventos https://es.javascript.info/event-delegation
• Animals
◦ Mammals
▪ Cows
▪ Donkeys
▪ Dogs
▪ Tigers
◦ Other
▪ Snakes
▪ Birds
▪ Lizards
• Fishes
◦ Aquarium
▪ Guppy
Requerimientos:
solución
La solución tiene dos partes.
1. Envuelve cada nodo de título del árbol dentro de <span> . Luego podemos aplicarles CSS-
style en :hover y manejar los clics exactamente sobre el texto, porque el ancho de <span>
es exactamente el ancho del texto (no lo será si no lo tiene).
2. Establece el manejador al nodo raíz del tree y maneja los clics en aquellos títulos
<span> .
Tabla ordenable
importancia: 4
Haz que la tabla se pueda ordenar: los clics en elementos <th> deberían ordenarla por la columna
correspondiente.
10 de 13 24/3/24, 19:13
Delegación de eventos https://es.javascript.info/event-delegation
1 <table id="grid">
2 <thead>
3 <tr>
4 <th data-type="number">Age</th>
5 <th data-type="string">Name</th>
6 </tr>
7 </thead>
8 <tbody>
9 <tr>
10 <td>5</td>
11 <td>John</td>
12 </tr>
13 <tr>
14 <td>10</td>
15 <td>Ann</td>
16 </tr>
17 ...
18 </tbody>
19 </table>
En el ejemplo anterior la primera columna tiene números y la segunda cadenas. La función de ordenamiento
debe manejar el orden de acuerdo al tipo de dato.
Ejemplo en funcionamiento:
Age Name
5 John
2 Pete
12 Ann
9 Eugene
1 Ilya
P.D. La tabla puede ser grande, con cualquier cantidad de filas y columnas.
solución
Abrir la solución en un entorno controlado.
11 de 13 24/3/24, 19:13
Delegación de eventos https://es.javascript.info/event-delegation
Comportamiento: Tooltip
importancia: 5
Cuando un mouse pasa sobre un elemento con data-tooltip , el tooltip debe aparecer sobre él, y
ocultarse cuando se va.
Desplaza la página para que los botones aparezcan arriba de todo, verifica que los
tooltips se muestren correctamente.
En esta tarea suponemos que todos los elementos con data-tooltip solo tienen texto dentro. Sin tags
anidados (todavía).
Detalles:
Usa delegación de eventos: prepare dos manejadores en el document para rastrear todos los “overs” y
“outs” de los elementos con data-tooltip y administra los tooltips desde allí.
Después de implementar el comportamiento, incluso gente no familiarizada con JavaScript puede agregar
elementos anotados.
12 de 13 24/3/24, 19:13
Delegación de eventos https://es.javascript.info/event-delegation
solución
Abrir la solución en un entorno controlado.
Comentarios
● Si tiene sugerencias sobre qué mejorar, por favor enviar una propuesta de GitHub o una solicitud
de extracción en lugar de comentar.
● Si no puede entender algo en el artículo, por favor explique.
● Para insertar algunas palabras de código, use la etiqueta <code> , para varias líneas –
envolverlas en la etiqueta <pre> , para más de 10 líneas – utilice una entorno controlado
(sandbox) (plnkr, jsbin, codepen…)
13 de 13 24/3/24, 19:13