Javascript Event Listeners

Overview

element.addEventListener('event', eventHandler);
  • element: is the HTML element to which you want to attach the click event listener. The HTML element can be selected using one of the many DOM selector elements.
  • event: is the name of the event to listen for. ('click', 'submit', 'keydown', etc)
  • eventHandler: is a callback function that will be executed when the click event occurs. The eventHandler takes a single parameter which is the event object commonly denoted as e.
element.addEventListener('event', e => { });

Handling the event callback

The eventHandler or callback, takes a single parameter which is the event object commonly denoted as e.

This event object gives different kinds of info. For example, where your mouse is, the screen size, and a whole lot more.

One of the most important items is the target. The target is essentially the he 'thing' or 'element' the event happened on.

<div class="app"></div>
const theTarget = document.querySelector('.app');
theTarget.addEventListener('event', e => console.log(e.target));
// outputs: <div class="app"></div>

Event Bubbling and Capturing

The short version

  • Bubbling goes from the target element up to the root of the DOM hierarchy.
  • Capturing, also known as 'trickling' goes from the root down to the target element.
Remember, bubbles go up, water trickles down.

Bubbling

Event bubbling is the default behavior in which an event starts from the target element that triggered it and then "bubbles up" through its parent elements in the DOM hierarchy. This means that the innermost element's event is triggered first, followed by its parent, and then its parent's parent, and so on, up to the top-level element (usually the document).

const grandparent = document.querySelector('.grandparent');
const parent = document.querySelector('.parent');
const child = document.querySelector('.child');

grandparent.addEventListener('click', (e) => console.log(`Grandparent clicked`));
parent.addEventListener('click', (e) => console.log(`Parent clicked`));
child.addEventListener('click', (e) => console.log('Child clicked'));

In this example, clicking the grandparent <div> triggers only the event associated with the grandparent. Clicking the parent <div> triggers events for both the grandparent and parent. And, as you might expect, clicking the child <div> triggers events for all three: grandparent, parent, and child.

Capturing

Event capturing (also known as Trickling) is the opposite of bubbling. It involves the event starting from the top-level element and "trickling down" through the nested elements to the target element that originally triggered the event.

Capturing is handled by passing a third parameter (options) to the event listener:

element.addEventListener('event', eventHandler, {capture: true});
const grandparent = document.querySelector('.grandparent');
const parent = document.querySelector('.parent');
const child = document.querySelector('.child');

grandparent.addEventListener('click', (e) => console.log(`Grandparent capture`), { capture: true });
parent.addEventListener('click', (e) => console.log(`Parent capture`), { capture: true });
child.addEventListener('click', (e) => { console.log('Child capture') }, { capture: true });

grandparent.addEventListener('click', (e) => console.log(`Grandparent bubble`));
parent.addEventListener('click', (e) => console.log(`Parent bubble`));
child.addEventListener('click', (e) => console.log('Child bubble'));

// Grandparent capture
// Parent capture
// Child capture
// Child bubble
// Parent bubble
// Grandparent bubble

Stop propagation (TBD)

Fire and event only once (TBD)

Remove event listeners (TBD)

Delegate events (TBD)

Examples

Run a function on click

element.addEventListener('click', functionName);

Add class on click

document.querySelector('.btn').addEventListener('click', () => {
    // Add your desired class name here (e.g., "new-class")
    const classNameToAdd = 'green';

    // Get the first element with the class "bx"
    const bxElement = document.querySelector('.bx');

    // Check if the element already has the class
    const hasClass = bxElement.classList.contains(classNameToAdd);

    // If the element does not have the class, add it; otherwise, remove it
    if (!hasClass) {
        bxElement.classList.add(classNameToAdd);
    } else {
        bxElement.classList.remove(classNameToAdd);
    }
});

function eventHandler(event) {
  if (event.type === "fullscreenchange") {
    /* handle a full screen toggle */
  } else {
    /* handle a full screen toggle error */
  }
}

Additional Resources

MDN EventTarget: addEventListener() method