Exercise 3: Event Delegation: List Click

Problem Statement

Given `<ul id="list">`, add single click listener on UL and detect which `<li data-id>` clicked. Return clicked id via callback.

Sample Output:

onListItemClick(ul, (id) => console.log(id))
// Click on <li data-id="123"> → callback called with "123"
// Click on <li data-id="456"> → callback called with "456"

Solution

const onListItemClick = (ul, cb) => {
  ul.addEventListener('click', (e) => {
    const li = e.target.closest('li[data-id]');
    if (li && ul.contains(li)) cb(li.dataset.id);
  });
};

Explanation

Overall Goal:

  • Event delegation: parent pe listener, child clicks detect karna.
  • Dynamic lists me efficient: har item pe listener nahi lagana.

Line 1: Function header

  • const onListItemClick = (ul, cb) => {
  • ul → parent <ul> element.
  • cb → callback function jo clicked id lega.

Line 2: Add event listener

  • ul.addEventListener('click', (e) => {
  • Parent ul pe listener lagaya (not individual li).
  • e → event object (click event details).

Line 3: Find clicked element

  • const li = e.target.closest('li[data-id]');
  • e.target → element jispe click hua (could be li ya uska child).
  • .closest('li[data-id]') → DOM traversal:
  • Current element se upar jata hai.
  • Pehla li[data-id] element find karta hai.
  • Example: click on <span> inside <li>closest finds parent <li>.

Line 4: Safety check and callback

  • if (li && ul.contains(li)) cb(li.dataset.id);
  • li → kya li element mila?
  • ul.contains(li) → kya li actually ul ka child hai? (security check).
  • Agar dono true → cb(li.dataset.id) → callback ko id pass karo.

Why event delegation?

  • Performance: ek listener vs N listeners (N = items count).
  • Dynamic: naye items add karne pe listener re-bind nahi karna.

Real world:

  • Todo lists: items add/remove hote rahte hain.
  • Product lists: filters se items change hote hain.
  • Chat messages: naye messages pe click handle.