DEV Community

Avinash
Avinash

Posted on

Deep dive into the browser events with mindmaps

This is an extensive exploration of the intricacies surrounding DOM events. First and foremost, we will delve into the various types of DOM events, examining each of their unique characteristics and how they are triggered. Additionally, we will take a closer look at some of the more commonly misunderstood aspects of DOM events, such as the propagation and bubbling of events.

What is a browser event?

Let's simply put it this way an event is an object which has the property that contains information about that particular event, such as on what element the event is triggered and many other information about that particular event.

DOM event mindmap

Events can be generalised into 2 categories

  • User-agent events
  • synthetic events

User-agent events are dispatched by the browser based on user interactions or any other browser(page) task is completed.

For example

  1. The user clicks on the button
  2. The user submits the form
  3. All the resources have been downloaded.

And may more, we can add a listener to the event in order to listen to the events

window.addEventlistner('load',(event)=>{console.log(event));
Enter fullscreen mode Exit fullscreen mode

Synthetic events

Synthetic events

On the other hand, synthetic events are the events that are created/emitted by applications.

For example

const event = new Event('myEvent', {bubbles:true, cancelable: true});

//dispatch events
document.dispatchEvent(event);

//events can be dispatched from any element
document.getElementbyId('myDiv').dispatchEvent(event)
Enter fullscreen mode Exit fullscreen mode

If we want to pass the data then we can use CustomEvent().

const event = new CustomEvent('myCustomEvent', {detail: {message:'hello world'});

elem.addEventListner('myCustomEven', (event)=>{
console.log(event.detial.message)
})
Enter fullscreen mode Exit fullscreen mode

The isTrusted is the property in the event object that is true for user-agent dispatched events and false for the applications(developers) initiated.

Event phase

Event Phase

When we further inspect the event object we also get a property name eventPhase. In order to understand this property let us first understand what is CAPTURING_PHASE and BUBBLEING_PHASE.

When an event is dispatched it will occur in the event will reach to document(root) and then back to the target element(in the above diagram button). The flow from top to bottom is called capturing phase and the bottom to top is called the *****bubbling phase.***** let us take a step forward and understand the above diagram with code

<!DOCTYPE html>
<html>

<head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
</head>

<body >
    <form id='submit_form' style="border:1px solid red; padding: 4rem">
    <button type='submit' id='submit_button'>Submit<button>
    </div>
    </form>

    <script>

            function eventListener(event) {
                        console.log({
                        target: event.target,
                        currentTarget: event.currentTarget,
                        phase: event.eventPhase,
                        type: event.type
                  });
            }

        const form = document.getElementById("submit_form");
        const buttonContainer = document.getElementById("button-wrapper");
        const submit = document.getElementById("submit_button");

        form.addEventListener("click", eventListener);
        buttonContainer.addEventListener("click", eventListener);
        submit.addEventListener("click", eventListener);

    </script>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

This is a long example let's break it down. We have a simple form and later we are attaching some event listeners to it. The addEventListner() function takes 3 arguments

  • event name that the event listener should listen
  • a callback function that should be called.
  • And the last one is an option or useCapture. It is an optional argument.

All the arguments are pretty much clear by the name the only argument that we care about is option and useCapture.

The option has these parameters.

  • capture: The default value is false. The event will first be captured with the current element to which the event listener is attached (i.e element above in the DOM tree) and then later will be dispatched to any event target
  • once: The events should be invoked once and removed by default
  • passive: If true it tells the browser that the callback functions will not have the preventDefault(). Even if the preventDefault is there in the callback function the browser will only throw and warning in the console.
  • signal: It's used for removing the event listener by providing the AbortSignal. We will talk about the abort signal later in this blog.

Capturing and bubbling phase

In the example above we have attached listeners at the document, body, form and button We run the above example the output will be like this

{target: button#submit_button, currentTarget: button#submit_button, phase: 2, type: 'click'}
{target: button#submit_button, currentTarget: div#button-wrapper, phase: 3, type: 'click'}
{target: button#submit_button, currentTarget: form#submit_form, phase: 3, type: 'click'}
Enter fullscreen mode Exit fullscreen mode

To understand this we first need to look into the Event object. The user agent-generated event object mainly has these properties

Event Object

  • type: The type is the type of event for e.g click, submit etc. You can read more about it here
  • eventTaget: Returns the element on which the event occurred or null.
  • currentTarget: Returns the element which is listening to the event
  • eventPhase: This one is the interesting one. The event phase generally returns one of these values 0,1,2,3. What are these values? The event phase has these enums
NONE = 0
CAPTURING_PHASE = 1;
AT_TARGET = 2;
BUBBELING_PHASE = 3;
Enter fullscreen mode Exit fullscreen mode

Let us understand each of these values one by one. In the above example context, the <button /> element is wrapped by a div, which is further nested inside a form. So when the button has been clicked the div and from are in the capturing phase. But in the console, we don't see any eventPhase as 1 (i.e capturing) event listener is not being invoked.

To invoke an event listener callback function in the capturing phase we need to specify true in the event listeners

 document.body.addEventListener("click", eventListener, true);

// or
 document.body.addEventListener("click", eventListener, { capture:true });
Enter fullscreen mode Exit fullscreen mode

Propagation

Now that we have a solid understanding of the event phases. Let us further look into how to stop handlers from getting called. We have 2 methods for stopping the propagation of the event.

  • event.stopPropagation() and
  • event.stopImmediatePropagation()

Assume we have multiple event handlers attached to an element. We have stopHandler() and eventListenerLogs()



<!DOCTYPE html>
<html>
   <head>
      <title>Parcel Sandbox</title>
      <meta charset="UTF-8" />
   </head>
   <body>
      <form id='submit_form' style="border:1px solid red; padding: 4rem">
         <div id='button-wrapper' style="border:1px solid black; padding: 4rem"">
            <button type='button' id='submit_button'>Submit<button>
         </div>
      </form>
      <script>
         function stopHandler(event) {
           event.stopPropagation();
           console.log({
             target: event.target,
             element: event.currentTarget,
             phase: event.eventPhase,
             type: event.type
           });
         }

         const form = document.getElementById("submit_form");

                    document.body.addEventListener("click", eventListener, false);
         form.addEventListener("click", stopHandler, false);
         form.addEventListener("click", eventListener, false);

      </script>  
   </body>
</html>
Enter fullscreen mode Exit fullscreen mode

We have attached the event handler to body, and form element. When we click on the button the event occurs in BUBBLEING_PHASE and the order of event propagation should be supposed to be

Propogation
But since we have event.stopPropagation(), at the form level. the console o/p is

{target: button#submit_button, element: form#submit_form, phase: 3, type: 'click'}

{target: button#submit_button, element: form#submit_form, phase: 3, type: 'click'}
Enter fullscreen mode Exit fullscreen mode

As we have to event handler attached to form element.

What if we want to only listen to the event only once then we can use event.stopImmediatePropagation()

function stopHandler(event) {
           event.stopImmediatePropagation();
           console.log({
             target: event.target,
             element: event.currentTarget,
             phase: event.eventPhase,
             type: event.type
           });
         }
Enter fullscreen mode Exit fullscreen mode

Now the output is

{target: button#submit_button, element: form#submit_form, phase: 3, type: 'click'}

Enter fullscreen mode Exit fullscreen mode

Cancelable

A cancelable event’s read-only property returns true or false based on how the event was initialized. Most of the native events are cancelable using event.preventDefault() . Calling this function is like the event never happened. We can create a syntheticEvent and make it non-cancelable.

const myCoustomEvent = new CoustomEvent("my-coustom",{
cancelable:true
})

document.addEventListener('my-event', function (event) {
   event.preventDefault()
})

console.log(
  document.dispatchEvent(event) ? 'Event was not cancelled' : 'Event was cancelled'
)

//output
//"Event was cancelled"
Enter fullscreen mode Exit fullscreen mode

If we change the cancelable property to false the output will be Event was not cancelled .

PreventDefault

event.preventDefault() will stop the native element action from happening. This means that the event will not work in the same way as if the event never happened.

Conclusion.

That concludes our discussion on events and how to create custom ones. We covered the various phases involved in triggering events and explored the cancelable event.

Thank you for reading. Please let me know in the comments section if I missed anything.

Top comments (1)

Collapse
 
fruntend profile image
fruntend

Сongratulations 🥳! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 👍