Free tutorials & notes in Hindi & English · Clean code examples 🧰 Free PDF & Image Tools →
🖱️ Days 8–14 – Data, DOM & Events  ·  Day 11

Day 11: Events, Event Object & Delegation

⏱ 95 min📶 Intermediate🎯 100% self-study
Day 11 / 30

✅ Today you will learn

  • addEventListener and the most useful event types
  • The event object: target, key, preventDefault
  • Bubbling, capturing and stopPropagation
  • Event delegation – one listener for many items
  • Keyboard shortcuts, once and removing listeners

🏢 In the real world

A product list shows 200 sweets. A junior developer added 200 separate click listeners – then new products loaded from the server and their buttons did not work at all. The fix is event delegation: one listener on the parent that handles every current and future button. It is a classic interview question and a daily tool.

addEventListener and event types

HTML + JavaScript
<button id="b">Click me</button>
<input id="i" placeholder="Type here…" aria-label="Type here">
<select id="s" aria-label="Size"><option>500 g</option><option>1 kg</option></select>
<div id="box" style="margin-top:8px;padding:16px;background:#fef3c7;border-radius:8px">Hover / double-click me</div>
<pre id="log" style="height:110px;overflow:auto;background:#111827;color:#a7f3d0;padding:8px;border-radius:8px"></pre>

<script>
const log = msg => {
  const box = document.querySelector('#log');
  box.textContent = msg + '\n' + box.textContent;
};
document.querySelector('#b').addEventListener('click', () => log('click'));
document.querySelector('#i').addEventListener('input', e => log('input: ' + e.target.value));
document.querySelector('#s').addEventListener('change', e => log('change: ' + e.target.value));
const box = document.querySelector('#box');
box.addEventListener('mouseenter', () => log('mouseenter'));
box.addEventListener('dblclick', () => log('dblclick'));
</script>
▶  Try each control – events appear at the top of the log
EventFires whenTypical use
clickMouse click, tap, Enter/Space on buttonsButtons, cards, menus
inputEvery keystroke / change in a fieldLive search, character counters, totals
changeValue committed (select, checkbox, blur)Filters, settings
submitA form is submittedValidate, then send with fetch
keydownA key is pressedShortcuts, Esc to close
focus / blurField gains / loses focusShow hints, validate on leave
scroll / resizePage scrolls / window resizesSticky effects (throttle them – Day 24)
DOMContentLoadedHTML parsedStart code (not needed with defer)

The event object

HTML + JavaScript
<a id="link" href="https://example.com">Go to example.com (blocked)</a>
<p>Press any key while this preview is focused…</p>
<p id="out"></p>

<script>
document.querySelector('#link').addEventListener('click', function (event) {
  event.preventDefault();                       // stop the default action (navigation)
  document.querySelector('#out').textContent = `Link click stopped. target: <${event.target.tagName.toLowerCase()}>`;
});
document.addEventListener('keydown', e => {
  document.querySelector('#out').textContent =
    `key: "${e.key}"  code: ${e.code}  ctrl: ${e.ctrlKey}  shift: ${e.shiftKey}`;
});
</script>
▶  event.preventDefault(), event.target and keyboard details
Property / methodMeaning
e.targetThe element that was actually clicked/typed in
e.currentTargetThe element the listener is attached to
e.preventDefault()Stop default behaviour (form submit reload, link navigation)
e.stopPropagation()Stop bubbling to parents (use rarely)
e.key / e.codeWhich key ("Enter", "Escape", "a")
e.ctrlKey / shiftKey / metaKeyModifier keys for shortcuts

Bubbling: events travel upwards

HTML + JavaScript
<div id="outer" style="padding:16px;background:#e0e7ff;border-radius:10px">outer div
  <div id="inner" style="padding:16px;background:#c7d2fe;border-radius:10px;margin-top:6px">inner div
    <button id="btn">button</button>
  </div>
</div>
<p id="path"></p>

<script>
const path = [];
['#btn', '#inner', '#outer'].forEach(sel => {
  document.querySelector(sel).addEventListener('click', e => {
    path.push(e.currentTarget.id);
    document.querySelector('#path').textContent = 'Order: ' + path.join(' → ');
  });
});
document.querySelector('#btn').addEventListener('click', () => { path.length = 0; }, { capture: true });
</script>
▶  Click the button: btn → inner → outer

Event delegation – the professional pattern

HTML + JavaScript
<ul id="products"></ul>
<button id="more">Load 2 more products</button>
<p id="cart">Cart: 0 items</p>

<script>
const all = ['Kaju Katli', 'Ghewar', 'Rasmalai', 'Ladoo', 'Kalakand', 'Soan Papdi'];
let shown = 2, cartCount = 0;
const list = document.querySelector('#products');

function render() {
  list.innerHTML = all.slice(0, shown).map((name, i) =>
    `<li>${name} <button data-action="add" data-index="${i}">Add</button>
                  <button data-action="info" data-index="${i}">Info</button></li>`).join('');
}

// ONE listener on the parent handles every button – even ones added later
list.addEventListener('click', e => {
  const btn = e.target.closest('button[data-action]');
  if (!btn) return;                                  // click was not on a button
  const name = all[Number(btn.dataset.index)];
  if (btn.dataset.action === 'add') {
    cartCount++;
    document.querySelector('#cart').textContent = `Cart: ${cartCount} items (last: ${name})`;
  } else {
    alert(`${name}: made fresh every morning`);
  }
});
document.querySelector('#more').addEventListener('click', () => { shown = Math.min(all.length, shown + 2); render(); });
render();
</script>
▶  New buttons work immediately because the parent listens
  1. 1Attach one listener to a stable parent (list, table, document)
  2. 2In the handler, find the real target with e.target.closest(selector)
  3. 3Return early if nothing matched
  4. 4Read data-* to know which item and which action
  5. 5Works for items rendered later – and uses less memory
Delegation recipe

Keyboard shortcuts, once and removing listeners

HTML + JavaScript
<button id="open">Open offer</button>
<div id="modal" hidden style="margin-top:10px;padding:16px;border:2px solid #ca8a04;border-radius:12px">🎁 10% off today! <small>(press Esc or click ✕)</small> <button id="x" aria-label="Close">✕</button></div>
<p><button id="once">Claim coupon (works once)</button> <span id="c"></span></p>

<script>
const modal = document.querySelector('#modal');
function onKey(e) { if (e.key === 'Escape') close(); }
function open() { modal.hidden = false; document.addEventListener('keydown', onKey); }
function close() { modal.hidden = true; document.removeEventListener('keydown', onKey); }   // same function reference!
document.querySelector('#open').addEventListener('click', open);
document.querySelector('#x').addEventListener('click', close);

document.querySelector('#once').addEventListener('click', () => {
  document.querySelector('#c').textContent = 'Coupon SWEET10 applied ✅';
}, { once: true });
</script>
▶  Esc closes the offer; the coupon button only works the first time
⚠️ removeEventListener needs the same function

An anonymous arrow function cannot be removed, because writing it again creates a new function. Store it in a named function (like onKey) when you plan to remove it.

🏅 Job skills unlocked today

✔ Listen to click, input, change, submit and key events✔ Use the event object and preventDefault✔ Understand bubbling and apply event delegation✔ Add shortcuts, one-time listeners and clean up

Practice tasks

🏋️ Practice – do it yourself

Task 1: Build a star rating: 5 ★ buttons inside one container; clicking the 3rd colours the first three gold. Use delegation.
Show solution
▶  Result
Task 2: Add a keyboard shortcut: pressing "/" focuses the search box (but not while typing in another input).
Task 3: In a table of orders, use one listener to delete a row when its 🗑 button is clicked.

Quick quiz

🧠 Quick Quiz – test yourself

1. Stop a form from reloading the page:
Default action stops.
2. Event for every keystroke in an input:
change waits for commit.
3. After clicking a button inside a div, the div’s click listener…
Events bubble up.
4. Event delegation means…
Uses bubbling.
5. { once: true } makes a listener…
Auto-removed.

Interview corner

💼 Interview Corner

Explain event bubbling and delegation.

After an event fires on a target it propagates up through its ancestors (bubbling). Delegation attaches one listener to a common ancestor and uses e.target/closest to decide which child triggered it – efficient for long or dynamic lists.

e.target vs e.currentTarget?

target is the innermost element where the event originated; currentTarget is the element whose listener is currently running (the one you attached to).

Summary

  • el.addEventListener("click", handler) – many event types.
  • e.target, e.key and e.preventDefault() are the daily helpers.
  • Events bubble; delegation = one parent listener + closest().
  • Use once, named handlers and removeEventListener to clean up.
➡️ Next

Day 12: create elements and render lists from data – the data → UI pattern used by React.

Frequently Asked Questions

onclick attribute or addEventListener?
addEventListener: you can add many listeners, remove them, use options like once/passive, and keep JS out of HTML.
Do clicks work on phones?
Yes, taps fire click events. For buttons use real <button> elements so keyboard and screen-reader users can trigger them too.
← JavaScript (30 Days)
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

Next topicDay 12: Create Elements & Render Lists from Data Your progress: 11 / 30 (37%) · Lesson 12 / 30 Continue →

How was this lesson?

Your feedback helps us make the content better.

Write a review or suggestion (optional)

After approval, your name and city may appear publicly with your review. Please do not write your email or phone number.

▶ CodingEasily on YouTube

Learn with video lessons in easy Hindi

Featured video: RDBMS Part 3 – Class XI Commerce IT

▶ Subscribe – it’s free