Eventos en Javascript (parte 2)

10-3-2020

Repasamos la captura de eventos con el escuchador:

//el callback está escrito en la forma tradicional de escribir una función
document.addEventListener('click', function(e) {...})

//con arrow functions
document.addEventListener('click', (e)=> {...})

En este punto agregamos a nuestra lista de elementos el "target", que es la propiedad que me permite individualizar el item el que le estoy capturando el evento. Para poder obtenerlo, tengo que pasar el objeto Evento como parámetro:

document.addEventListener('click', function(e) {
    if(e.target.id == 'dinamico') {
        console.log('click en dinámico')
    }
})

 

Cómo capturar un elemento dinámico

En este ejemplo solucionamos le problema de querer capturar un elemento que se genera dinámicamente. Si el evento no está en el html original, sino que se genera cuando, por ejemplo, el usuario realiza alguna acción, no podemos capturar dicho elemento como veníamos haciendo con document.getElementById() ni tampoco ninguna de sus alternativas, como document.querySelector(), porque el código que quiere atrapar dicho elemento (que inicia siendo inexistente), se ejecuta al principio, y si el usuario aún ni hizo click, por ejemplo, el elemento en cuestión aún no existe y es NULL.

Veamos cómo lo resolvemos:

//estático es el id de un botón que ya existe en la página
var estatico = document.getElementById('estatico')

/*agregamos un elemento que nos permita no generar un nuevo botón cada vez que clickeamos el botón estático. Para evitar que se repita, generamos una variable que está en false y sólo se vuelve true cuando generamos el botón por primera vez. Y si está en true el botón dinámico no se genera.
*/
var yaCreado = false

//agregamos el escuchador al botón estático
estatico.addEventListener('click', function () {
    console.log('click en estático')
    //si la variable yaCreado es false 
    if (!yaCreado) {
        //creamos el botón, le asignamos un id y un texto
        let dinamico = document.createElement('button')
        dinamico.id = 'dinamico'
        dinamico.innerText = 'DINAMICO'
        //y lo agregamos a la página
        document.body.appendChild(dinamico)
        //y finalmente yaCreado pasa a ser true, para que ya no se genere otra vez
        yaCreado = true
    }
})

// ---------------------------------------------------------------------------------
// Asociación del evento de click del botón dinámico mediante propagación de eventos
// ---------------------------------------------------------------------------------
document.addEventListener('click', function(e) {
    if(e.target.id == 'dinamico') {
        console.log('click en dinámico')
    }
})

 

Prevenir Eventos Automáticos

Los eventos automáticos (no los generados por el usuario) pueden cancelarse usando preventDefault(), que es un método del objeto e (recordemos que es el evento en sí).

Cuando hablamos e eventos automáticos nos referimos a los eventos que el navegador hace por defecto, por ejemplo, clickear un link hace un reload de la página, porque el navegador trata de ir a es link, y aunque esté vacío lo intenta.

Si queremos detener eso, usamos e.preventDefault(), así como está, antes de hacer cualquier otra cosa con el elemento.

let link = document.getElementById('link')
link.addEventListener('click', function(e) {
    e.preventDefault()
    console.log('Click en enlace sin reload')
})

Podemos trabajar también con elementos del BOM desde el DOM, asignando un escuchador al window en lugar del document.

Vale aclarar que al referenciar una propiedad del window, por ejemplo outerWidth, no necesitamos poner window.outerWidth sino que alcanzaría con outerWidth, pero en el ejemplo se agregó para mayor claridad.

let info = document.getElementById('info')
window.addEventListener('resize', () => {
    //console.log('Cambió el tamaño!')
    info.innerText = `El tamaño externo del navegador es ${window.outerWidth} px de ancho por ${window.outerHeight} de alto.
    El tamaño interno del navegador es ${window.innerWidth} px de ancho por ${window.innerHeight} de alto `  
})

En el ejemplo usamos además la backtic (`), que es una nueva forma de notación en JS6, que sinceramente es muy práctica.

Sirve para escribir de corrido strings y agregarle variables sin necesidad de concatenar los elementos. En este caso, las variables se escriben entre llaves de esta manera ${mi variable}.

 

Creando mis propios eventos

Usando new Event podemos generar un nuevo objeto del tipo evento. En JS5 es una función constructora, mientras que en JS6 ya funciona como una clase, aplicando la forma de trabajar con objetos de los demás lenguajes.

//metemos nuestro evento en el objeto ev1, que es una variable
//look es el nombre que decido llamar al evento en sí
var ev1 = new Event('look', {
                              'bubbles': true, 
                              'cancelable': false
})


Bubbles y cancelable son propiedades del objeto Evento en JS. Para ver toda la lista de propiedades podemos consultar la documentación existente en MDN o en W3Schools (entre muchos otros).

Una vez generado el objeto Evento, vamos a asignarle un escuchador a algún elemento de la página para que nuestro evento sea usado.

//creamos uno o más eventos
var ev1 = new Event('look', {'bubbles': true, 'cancelable': false})
var ev2 = new Event('look2', {'bubbles': true, 'cancelable': false})
var ev3 = new Event('look3', {'bubbles': true, 'cancelable': false})

//asignamos el evento -en este caso al documento directamente-
document.addEventListener('look', () => {
    console.log('look')
})

//podemos agregar sucesivos eventos
document.addEventListener('look2', () => {
    console.log('look2')
})

document.addEventListener('look3', () => {
    console.log('look3')
})

//Finalmente, puede ser más sencillo y rápido CONCATENAR lo que queremos hacer de la siguiente manera:

document.getElementById('generar-evento-1')
.addEventListener('click', () => {
    document.dispatchEvent(ev1)
    document.dispatchEvent(ev3)
})

document.getElementById('generar-evento-2')
.addEventListener('click', () => {
    document.dispatchEvent(ev2)
})

 

El método dispatchEvent() nos permite activar o "despachar" el evento que queremos en un momento dado.