DEV Community

Cover image for A Guide to Handling Browser Events

A Guide to Handling Browser Events

Sarah Chima on April 16, 2019

Cover Photo by Ambitious Creative Co. - Rick Barrett on Unsplash Most web pages are interactive and users can perform actions on the web page. ...
Collapse
 
karataev profile image
Eugene Karataev

Thanks for the article, Sarah.
One question about the browser events bothers me for some time. You mentioned the third parameter useCapture when adding a listener to a DOM node. When readng fellow developers code sometimes I see boolean values true/false, sometimes objects {useCapture: true}. What's the difference between them? And what was the purpose to implement both options in browsers if there is no difference between them?

Collapse
 
nickytonline profile image
Nick Taylor

Sarah mentions it in the article. 😀

"The difference between bubbling and capturing is that in the bubbling phase, events propagate outwards. That is, the handler on the innermost element gets triggered first, then the parent all the way up.

In capturing, the reverse occurs. The handler on the outermost element is triggered first and then the child handler all the way down to the element where the event occurred. "

Collapse
 
karataev profile image
Eugene Karataev

I mean there are two ways to add event listener in capture phase:

  1. node.addEventListener('click', e => console.log(e.eventPhase), true);
  2. node.addEventListener('click', e => console.log(e.eventPhase), {capture: true});

The result will be the same.
So my question was: is there any difference in these statements or they do exactly the same thing?

Thread Thread
 
sarah_chima profile image
Sarah Chima

Hi Eugene.

They do exactly the same thing. true is a shorthand for {capture: true}.

Thanks for reading my article.

Thread Thread
 
nickytonline profile image
Nick Taylor

Ahh, sorry misunderstood what you were asking. 🙃 I believe Sarah just answered you.

Collapse
 
thefoxboxman profile image
John De Costa

Excellent explanation Sarah. Keep up this great work.

Collapse
 
sarah_chima profile image
Sarah Chima

Thank you John.

Collapse
 
budyk profile image
Budy • Edited

Thanks for sharing.. Just want to add, using arrow function as eventListener callback will make the element lose the this context...

var span = document.querySelector('span');
span.addEventListener('click', (event) => {
   console.log(this); // Window Object
}

compared to this

var span = document.querySelector('span');
span.addEventListener('click', function(event) {
   console.log(this); // Element Object
   this.innerHTML = 'Hola';
}
Collapse
 
fc250152 profile image
Nando

Budy, sorry but I don't notice any difference in the two snippets ... maybe the latter should be a regular function declaration such as "function(event) {...}" ?
thank you, happy Easter!

Collapse
 
budyk profile image
Budy

Sorry, I've updated the snippet :)

Collapse
 
wesgrimes profile image
Wes

Nice summary 👌

Collapse
 
nickytonline profile image
Nick Taylor

Great explanation Sarah. Bubbling is so powerful because it allows you to reduce the potential number of events added to a page. Too many events can bog down a site.

I did a hello world in web components a couple of years ago, but haven't touched them since. Thanks for the refresher!

I'd just make one suggestion about adding event listeners. This is not web component specific, but for adding event listeners in general. In the case of the rainbow-text component, the number of <span />s increases for every additional letter in the text attribute, so the number of event listeners per instance of the component is n letters * 2 (mouse over + animation end events).

You can end up with a lot of events very quickly just for one instance of the component. What you can do is add an event listener for each event type on the parent <div /> you create in aspittel/rainbow-word-webcomponent and then the power of event bubbling is your friend.

e.g.

class RainbowText extends HTMLElement {
  …

  addEventListeners(div) {
    div.addEventListener("mouseover", e => {
      const { target } = e;

      if (target.tagName === "SPAN") {
        target.classList.add("hovered");
        console.log(`mousing over ${target.tagName}`);
      }
    });

    div.addEventListener("animationend", e => {
      const { target } = e;

      if (target.tagName === "SPAN") {
        target.classList.remove("hovered");
        console.log(`mousing over ${target.tagName}`);
      }
    });
  }

  …

  render() {
    const div = document.createElement("div");
    div.classList.add("header");
    this.addEventListeners(div);
    this.shadowRoot.appendChild(div);
    this.addSpans(div);
    this.addStyle();
  }
}
Collapse
 
madiallo profile image
Mamadou Alpha Diallo

great code

Collapse
 
fc250152 profile image
Nando

thank you, Sarah. simple and clear. have nice days

Collapse
 
annarankin profile image
Anna Rankin

This is a great overview, thank you Sarah! Always love to see great vanilla JS resources.