Event Delegation in JavaScript: Efficient Event Handling for Dynamic Elements


Event delegation is a technique in JavaScript that allows you to handle events on parent elements rather than directly attaching event listeners to individual child elements. With event delegation, you can efficiently manage events for dynamically added or removed elements within a container.

The concept behind event delegation is based on event propagation, which includes two phases: capturing and bubbling. When an event occurs on a DOM element, it first goes through the capturing phase, where the event is triggered on the parent elements starting from the top of the DOM hierarchy and moving towards the target element. After the capturing phase, the event enters the bubbling phase, where it triggers on the target element and then propagates up through the parent elements.

Event delegation takes advantage of event bubbling. Instead of attaching an event listener to each individual child element, you attach a single event listener to the parent element. When an event occurs on a child element, it bubbles up to the parent element and triggers the event listener attached to the parent. The parent element then determines which child element triggered the event by inspecting the event.target property.

The main advantages of event delegation are:

  1. Efficiency: With event delegation, you can handle events for a large number of elements efficiently, as you only need to attach a single event listener on the parent element rather than multiple listeners on each child element. This is especially useful when dealing with dynamically added or removed elements.
  2. Dynamic Element Handling: Event delegation allows you to handle events on dynamically added or removed elements without the need to attach and detach event listeners manually. The parent element remains constant, so it can handle events even for elements that are added or removed dynamically.
  3. Simplified Code: By using event delegation, you can write cleaner and more concise code by avoiding the need to attach event listeners to each individual element. This leads to better code maintainability and reduces the chances of memory leaks due to forgotten or orphaned event listeners.

Example - 1

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Event Delegation</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="container">
      <h3>Event Delegation in JavaScript</h3>
      <div id="categories">
        <div class="product" id="Laptops">Laptops</div>
        <div class="product" id="cameras">Cameras</div>
        <div class="product" id="printer">Printer</div>
        <div class="product" id="tv">TV</div>
        <div class="product" id="ac">AC</div>
        <div class="product" id="mobiles">Mobiles</div>
      </div>
    </div>
    <script src="delegation.js"></script>
  </body>
</html>

style.css

@import url("https://fonts.googleapis.com/css2?family=Lobster&family=Poppins:wght@100;200;300;400;500;600;700;800&display=swap");

* {
  font-family: "Poppins", sans-serif;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  width: 100vw;
  height: 100vh;
  display: grid;
  place-items: center;
}

.container {
  width: 650px;
  background-color: #333;
  padding: 10px;
}

h3 {
  font-weight: 300;
  font-size: 25px;
  margin: 10px 5px;
  color: #fff;
  text-align: center;
}

#categories {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.product {
  width: 150px;
  height: 150px;
  background-color: palegreen;
  text-align: center;
  line-height: 150px;
  color: brown;
  font-weight: 400;
  font-size: 18px;
  cursor: pointer;
}

delegation.js

const catagories = document.getElementById("categories");

catagories.addEventListener("click", function (e) {
  //console.log(e.target);
  if (e.target.className == "product") {
    //console.log(e.target.id);
    window.location.href = "/" + e.target.id;
  }
});

This code snippet demonstrates an event listener that handles a click event on an element with the ID "categories". Let's break it down step by step:

const catagories = document.getElementById("categories");

This line fetches the DOM element with the ID "categories" and assigns it to the variable catagories. It assumes there is an HTML element with the ID "categories" in the document.

catagories.addEventListener("click", function (e) {
  // Code to execute when the click event occurs
});

The addEventListener() method is called on the catagories element to attach a click event listener to it. The event listener will be triggered when a click event happens on the element.

The provided function (e) => {...} is the event handler that will be executed when the click event occurs. The e parameter represents the event object, which contains information about the event.

if (e.target.className == "product") {
  // Code to execute if the clicked element has the class "product"
}

Inside the event handler, this if statement checks if the element that triggered the click event has a CSS class name equal to "product". This is done by accessing the className property of the e.target element, which represents the actual element that was clicked.

If the condition is true, it means the clicked element has the class "product", and the code inside the if block will be executed.

window.location.href = "/" + e.target.id;

This line sets the window.location.href property to a new URL. It concatenates "/" with the id property of the clicked element (e.target.id). The resulting URL will navigate the user to a new page, using the value of the clicked element's ID as part of the URL path.

In summary, this code listens for click events on the "categories" element. If the clicked element has the class "product", it retrieves its ID and redirects the user to a new page using that ID as part of the URL path.

Example - 2

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <form action="#" id="frm">
      <div class="form-group">
        <label for="firstName">First Name</label>
        <input type="text" placeholder="Enter First Name" data-uppercase />
      </div>
      <div class="form-group">
        <label for="lastName">Last Name</label>
        <input type="text" placeholder="Enter Last Name" data-uppercase />
      </div>
    </form>
    <script src="script.js"></script>
  </body>
</html>

style.css

@import url("https://fonts.googleapis.com/css2?family=Lobster&family=Poppins:wght@100;200;300;400;500;600;700;800&display=swap");

* {
  font-family: "Poppins", sans-serif;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  width: 100vw;
  height: 100vh;
  display: grid;
  place-items: center;
  background-color: aliceblue;
}

#frm {
  width: 650px;
  background-color: #fff;
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.form-group {
  display: flex;
  flex-direction: column;
  margin-bottom: 10px;
}

.form-group label {
  margin-bottom: 5px;
}

.form-group input {
  border: 1px solid #ccc;
  padding: 5px 10px;
  border-radius: 3px;
  outline: none;
}

script.js

const frm = document.getElementById("frm");

frm.addEventListener("keyup", (e) => {
  if (e.target.dataset.uppercase != undefined) {
    e.target.value = e.target.value.toUpperCase();
  }
});

This code snippet demonstrates an event listener that handles the "keyup" event on a form element with the ID "frm". Here's a breakdown of how it works:

const frm = document.getElementById("frm");

This line fetches the form element with the ID "frm" from the DOM and assigns it to the variable frm. It assumes there is an HTML form element with the ID "frm" in the document.

frm.addEventListener("keyup", (e) => {
  // Code to execute when the keyup event occurs
});

The addEventListener() method is called on the frm form element to attach a "keyup" event listener to it. The event listener will be triggered when a key is released after being pressed within the form element.

The provided arrow function (e) => {...} is the event handler that will be executed when the keyup event occurs. The e parameter represents the event object, which contains information about the event.

if (e.target.dataset.uppercase != undefined) {
  e.target.value = e.target.value.toUpperCase();
}

Inside the event handler, this if statement checks if the element that triggered the keyup event has a "data-uppercase" attribute. It uses the dataset property of the e.target element to access custom data attributes.

If the condition is true, it means the element has the "data-uppercase" attribute, indicating that the value entered in the form element should be converted to uppercase. In that case, the line e.target.value = e.target.value.toUpperCase(); sets the value of the form element to its uppercase version.

In summary, this code listens for keyup events within the "frm" form element. If the element has a "data-uppercase" attribute, it automatically converts the entered value to uppercase. This functionality can be useful for enforcing uppercase input in specific form fields.

To implement event delegation, you attach an event listener to the parent element and use conditional statements to determine which child element triggered the event based on the event.target. You can then perform the desired actions or event handling logic accordingly.

Event delegation is commonly used in scenarios where you have a list or a container with multiple elements that require similar event handling, such as a dynamic list of items, a table, or a menu. It provides a scalable and efficient approach to handling events in these situations.

List of Programs


JS Practical Questions & Answers


JS Practical Project