Understanding JavaScript Event Listeners: A Beginner's Guide to Event Handling
In web development, it's common to need specific actions to occur when a user triggers an event, such as a click or keypress. To handle these scenarios, we use event listeners
, which detect the specified event and execute the necessary actions. Let's explore how to attach and manage event listeners effectively.
To attach an event listener to an element, we use the addEventListener
method. It requires three arguments. The first argument is the type of the event (e.g., click, double click, keydown). The second argument is a callback function that will be executed when the event occurs. The callback will receive an event object, which contains information about the event, such as which element triggered the event, the cursor position, window size, etc. The third parameter has a default value of false
, which we will discuss later in the article. For now, just remember that it exists.
Let's create a simple web page with a single button with the ID "button". We will attach an event listener that triggers every time the button is clicked.
If you're thinking we can directly use onclick
in the HTML or add onclick()
using a script, you're correct—they will do the job.
<!DOCTYPE html>
<html lang="en">
<head> ... </head>
<body>
<button onclick="doWork()">Click Me</button>
<button id="button">Click Here</button>
</body>
<script>
function doWork() {
console.log("Work is done!!!");
}
document.getElementById("button").onclick = () => {
doWork();
};
</script>
</html>
However, managing <button onclick={}>
can become troublesome as the project grows. onClick()
doesn't provide as much functionality as an event listener.
Now, back to the event listener. First, we will select the element using querySelector
or getElementById
.
To attach the event to the element, we use .addEventListener()
:
<body>
<button id="button">Click Here</button>
</body>
<script>
document.getElementById("button").addEventListener(
"click",
(e) => {
console.log("Event has been Triggered");
console.log(e);
},
false
);
</script>
Remember what was said earlier: the first parameter is the type of event (i.e., "click" in this example), the second parameter is a callback that will receive an event object e
, and the third parameter is a boolean with a default value of false
. We'll explore what it does later in the blog.
In the callback, there are two console.log
statements—one prints "Event has been triggered," and the other prints the event object e
to see what's inside. When you inspect the event object in the console, you'll realize it's a very large object, containing lots of details about the event.
Event Propagation
Now we've seen how to add an event to an element, but what if a parent element and its child element both have events attached to them? What will happen when the child element is clicked? Whose event will be triggered, the parent's or the child's? Which event will be executed first? Instead of giving you the answer right away, why don't we try it first?
Let's see with a simple example. First, we will create a parent element, which will be a div with the ID 'parent', and it will have a button element as a child with the ID 'child'. We will attach a click event to both the parent (div) and the child (button). The parent's event prints "Event triggered by parent" to the console, and the child's event prints "Event triggered by child."
<body>
<div id="parent">
<button id="child">Cick the Child</button>
</div>
</body>
<script>
document.getElementById("parent").addEventListener(
"click",
(e) => {
console.log("Event get trigger by parent");
},
false
);
document.getElementById("child").addEventListener(
"click",
(e) => {
console.log("Event get trigger by child");
},
false
);
</script>
After clicking the button
, what is printed in the console is:
Event get trigger by child
Event get trigger by parent
As you can see both parent's and child's event get trigger, first the child event gets trigger then the parent event. This is called event bubbling, like a bubble go up, the event get propagate from bottom of the tree to the higher level in tree.
What if our use case requires the event to propagate from parent to child? How do we do that?
Event propagation from child to parent is called event bubbling, while event propagation from parent to child is called event capturing. How do we achieve this?
Do you remember the addEventListener
method's third parameter, which is a boolean with a default value of false
? That parameter allows us to decide whether we want event bubbling (value set to false
), which is the default, or event capturing (value set to true
).
document.getElementById("parent").addEventListener(
"click",
(e) => {
console.log("Event get trigger by parent");
},
true
);
document.getElementById("child").addEventListener(
"click",
(e) => {
console.log("Event get trigger by child");
},
false
);
As you can see, to enable event capturing, we simply change the boolean value in the parent’s event listener to true
. Whether the value is true
or false
determines the propagation order from parent to child. The child’s true/false
setting will only affect its own children, if any.
Stopping Propagation
document.getElementById("parent").addEventListener(
"click",
(e) => {
console.log("Event get trigger by parent");
e.stopPropagation()
},
true
);
document.getElementById("child").addEventListener(
"click",
(e) => {
console.log("Event get trigger by child");
},
false
);
To stop propagation from parent to child, use e.stopPropagation()
in the parent’s callback. To stop propagation from child to parent, use e.stopPropagation()
in the child’s callback.
I encourage you to experiment with event propagation to deepen your understanding. Try creating a parent, child, and grandchild element, then add event listeners to observe the order of execution. I’ve provided a basic example here—feel free to explore and tweak it. I hope this article has helped you grasp the basics of event handling. Stay tuned for my next article, where we'll dive into more advanced topics. In the meantime, keep experimenting with event propagation. Happy coding!