Home > other >  Event delegation on non nested elements
Event delegation on non nested elements

Time:11-06

I'm using Bootstrap group radio button on which I would like to write event delegation.

<div  role="group" aria-label="Basic radio toggle button group">
  <input type="radio"  name="btnradio" id="btnradio1" autocomplete="off" checked>
  <label  for="btnradio1">Radio 1</label>

  <input type="radio"  name="btnradio" id="btnradio2" autocomplete="off">
  <label  for="btnradio2">Radio 2</label>

  <input type="radio"  name="btnradio" id="btnradio3" autocomplete="off">
  <label  for="btnradio3">Radio 3</label>
</div>

Since the labels are not nested in the button, the following is not returning the inputs.

event.target.closest('.btn-check');

Is there a proper way to write event delegation on this type of non-nested elements?

CodePudding user response:

Here is how. Clicking the radio OR the label will show the ID. No need for closest here, but closest WILL return the element itself if it matches the selector

In Bootstrap it also works

document.querySelector('.btn-group').addEventListener('click', (e) => {
  const tgt = e.target;
  if (tgt.matches('.btn-check')) console.log(tgt.id)
});
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">

<div  role="group" aria-label="Basic radio toggle button group">
  <input type="radio"  name="btnradio" id="btnradio1" autocomplete="off" checked>
  <label  for="btnradio1">Radio 1</label>

  <input type="radio"  name="btnradio" id="btnradio2" autocomplete="off">
  <label  for="btnradio2">Radio 2</label>

  <input type="radio"  name="btnradio" id="btnradio3" autocomplete="off">
  <label  for="btnradio3">Radio 3</label>
</div>

If you have buttons with child elements, you DO need closest

Clicking the button text OR the icon will show the ID

document.querySelector('.btn-group').addEventListener('click', (e) => {
  const tgt = e.target.closest('.btn'); // would not work on the icon without closest
  if (tgt) console.log(tgt.id)
});
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" integrity="sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA==" crossorigin="anonymous" referrerpolicy="no-referrer" />

<div  role="group" aria-label="Basic button group">
  <button type="button"   id="btn1">Text</button>
  <button type="button"   id="btn2" ><i  aria-hidden="true"></i></button>
</div>

CodePudding user response:

In this code, i use the event delegation technique to listen for click events on the parent container with the class btn-group. When a click event occurs, we check if the clicked element is an <input> element with the type "radio", and if so, we log its ID to the console

  document.querySelector('.btn-group').addEventListener('click', (event) => {
    if (event.target.tagName === 'INPUT' && event.target.type === 'radio') {
      console.log(event.target.id);
    }
  });
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">

<div  role="group" aria-label="Basic radio toggle button group">
  <input type="radio"  name="btnradio" id="btnradio1" autocomplete="off" checked>
  <label  for="btnradio1">Radio 1</label>

  <input type="radio"  name="btnradio" id="btnradio2" autocomplete="off">
  <label  for="btnradio2">Radio 2</label>

  <input type="radio"  name="btnradio" id="btnradio3" autocomplete="off">
  <label  for="btnradio3">Radio 3</label>
</div>

  • Related