दिन 11: Events, Event Object और Delegation
✅ आज आप सीखेंगे
- addEventListener और सबसे उपयोगी event types
- Event object: target, key, preventDefault
- Bubbling, capturing और stopPropagation
- Event delegation – कई items के लिए एक listener
- Keyboard shortcuts, once और listeners हटाना
🏢 असली दुनिया में
Product list में 200 मिठाइयाँ हैं। एक junior developer ने 200 अलग click listeners जोड़े – फिर server से नए products आए और उनके buttons बिल्कुल नहीं चले। इलाज event delegation है: parent पर एक listener जो हर मौजूदा और भविष्य के button को संभाले। यह क्लासिक interview सवाल और रोज़ का औज़ार है।
addEventListener और event types
<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>| Event | कब चलता है | आम उपयोग |
|---|---|---|
| click | Mouse click, tap, buttons पर Enter/Space | Buttons, cards, menus |
| input | Field में हर keystroke / बदलाव | Live search, character counters, totals |
| change | Value पक्की (select, checkbox, blur) | Filters, settings |
| submit | Form submit | Validate करके fetch से भेजना |
| keydown | Key दबी | Shortcuts, Esc से बंद |
| focus / blur | Field focus पाए / खोए | Hints दिखाना, छोड़ने पर validate |
| scroll / resize | Page scroll / window resize | Sticky effects (throttle करें – Day 24) |
| DOMContentLoaded | HTML parse हुआ | Code शुरू (defer के साथ ज़रूरी नहीं) |
Event object
<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>| Property / method | मतलब |
|---|---|
| e.target | जिस element पर असल में click/type हुआ |
| e.currentTarget | जिस element पर listener लगा है |
| e.preventDefault() | Default व्यवहार रोकें (form submit reload, link navigation) |
| e.stopPropagation() | Parents तक bubbling रोकें (कम इस्तेमाल) |
| e.key / e.code | कौन सी key ("Enter", "Escape", "a") |
| e.ctrlKey / shiftKey / metaKey | Shortcuts के लिए modifier keys |
Bubbling: events ऊपर जाते हैं
<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>Event delegation – professional pattern
<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>- 1एक स्थिर parent (list, table, document) पर एक listener लगाएँ
- 2Handler में e.target.closest(selector) से असली target ढूँढें
- 3कुछ न मिले तो जल्दी return
- 4कौन सा item और कौन सा action – data-* से पढ़ें
- 5बाद में render हुए items के लिए भी चलता है – और कम memory
Keyboard shortcuts, once और listeners हटाना
<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>Anonymous arrow function हटाया नहीं जा सकता, क्योंकि दोबारा लिखने पर नया function बनता है। हटाना हो तो named function (जैसे onKey) में रखें।
🏅 आज के Job Skills
Practice tasks
🏋️ Practice – ख़ुद करें
Solution देखें
Quick quiz
🧠 Quick Quiz – ख़ुद को जाँचें
Interview corner
💼 Interview Corner
Event bubbling और delegation समझाइए।
Target पर event होने के बाद वह ancestors से ऊपर जाता है (bubbling)। Delegation साझा ancestor पर एक listener लगाकर e.target/closest से तय करता है किस child ने trigger किया – लंबी या dynamic lists के लिए कुशल।
e.target बनाम e.currentTarget?
target वह सबसे अंदर का element है जहाँ event शुरू हुआ; currentTarget वह element है जिसका listener अभी चल रहा है (जिस पर आपने लगाया)।
सारांश
- el.addEventListener("click", handler) – कई event types।
- e.target, e.key और e.preventDefault() रोज़ के helpers।
- Events bubble होते हैं; delegation = parent पर एक listener + closest()।
- सफ़ाई के लिए once, named handlers और removeEventListener।
Day 12: elements बनाना और data से lists render करना – React वाला data → UI pattern।
