meowalarm
meowalarm

Reputation: 5

How to add event delegation to "change" event (not click) on radio buttons?

I often times easily implemented event delegation with the "click" event on parent elements of something with code like

HTML:

<div>
  <span>
    <input
      type="radio"
      id="all0"
      name="difficulty-ask"
      class="difficultyaskclass"
      value="all"
      checked="checked"
    />
    <label for="all0">All</label>
    <input
      type="radio"
      id="2easy1"
      name="difficulty-ask"
      class="difficultyaskclass"
      value="easy"
    />
    <label for="2easy1">Easy</label>
    <input
      type="radio"
      id="2med2"
      name="difficulty-ask"
      class="difficultyaskclass"
      value="medium"
    />
    <label for="2med2">Medium</label>
    <input
      type="radio"
      id="2hard3"
      name="difficulty-ask"
      class="difficultyaskclass"
      value="hard"
    />
    <label for="2hard3">Hard</label>
  </span>
</div>

JS:

parentelement.addEventlistener('click', (event) => {
if(event.target.classList.contains('targetelement'){Code..}};

(parentelement is just a regular div, in which the radio buttons are placed)

How does it work now with the 'change' event for example for radio buttons if they switch state?

I made it work first by just looping through all of them and then add an eventListener to each. But this is obviously not the desired solution, i definitely need some event delegation there.

Upvotes: 0

Views: 95

Answers (3)

Mark Schultheiss
Mark Schultheiss

Reputation: 34217

This can be done pretty simply; here I also added some buttons to show the value and also clear the output - all so you can see the output and also show how to clear the radio value with code.

const container = document.querySelector(".container-parent");
const output = document.querySelector(".output");
const clear = document.querySelector(".clear-radio");

function handleChange(event) {
  output.innerHTML += `<div class="line">You changed to a ${event.currentTarget.tagName} element<br/>` +
    `Change was "${event.target.value}" value</div>`;
}

function handleClearRadio(event) {
  const radios = document.getElementsByName("radioflyer");
  const cked = [...radios].filter((el) => {
    return !!el.checked;
  });
  const hasChecked = !!cked.length;
  let v;
  if (hasChecked) {
    v = cked[0].value;
    cked[0].checked = false;
  }
  /*could be done in a loop but not needed for radios as cked[0].checked = false; works fine
    for (let i = 0; i < radios.length; i++) {
      radios[i].checked = false;
    }
    */
  output.innerHTML += `<div class="line">You cleared radios: ${hasChecked}<br/>` +
    `Clear was "${v}" value</div>`;
}

container.addEventListener("change", handleChange, {
  capture: true
});
clear.addEventListener("click", handleClearRadio, {
  capture: true
});
document.querySelector(".clear-output").addEventListener("click", function(event) {
  output.innerHTML = "Cleared";
});
.output {
  border: solid 1px #00ff00;
}

.output .line {
  border: solid 1px #0000ff;
  margin: 0.5em;
}

.container-parent {
  border: solid 1px #00ff00;
  padding: 0.5em;
  margin-bottom: 1em;
}
<form>
  <fieldset>
    <legend>Please select your preferred wagon order:</legend>
    <div class="container-parent">
      <label><input type="radio" class="radio-wins" value="first" name="radioflyer" />First</label>
      <label><input type="radio" class="radio-wins" value="second" name="radioflyer" />Second</label>
      <label><input type="radio" class="radio-wins" value="third" name="radioflyer" />Third</label>
    </div>
    <button type="button" class="clear-radio">Clear Radio</button>
    <button type="button" class="clear-output">Clear Output</button>
    <div class="output">
      Output will go here
    </div>
  </fieldset>
</form>

Same as above but JUST the questions code

const container = document.querySelector(".container-parent");

function handleChange(event) {
  //do something on change
  console.log(`Change was "${event.target.value}" value`);
}

container.addEventListener("change", handleChange, {
  capture: true
});
.container-parent {
  border: solid 1px #00ff00;
  padding: 0.5em;
  margin-bottom: 1em;
}
<div class="container-parent">
  <span>
    <input
      type="radio"
      id="all0"
      name="difficulty-ask"
      class="difficultyaskclass"
      value="all"
      checked="checked"
    />
    <label for="all0">All</label>
    <input
      type="radio"
      id="2easy1"
      name="difficulty-ask"
      class="difficultyaskclass"
      value="easy"
    />
    <label for="2easy1">Easy</label>
    <input
      type="radio"
      id="2med2"
      name="difficulty-ask"
      class="difficultyaskclass"
      value="medium"
    />
    <label for="2med2">Medium</label>
    <input
      type="radio"
      id="2hard3"
      name="difficulty-ask"
      class="difficultyaskclass"
      value="hard"
    />
    <label for="2hard3">Hard</label>
  </span>
</div>

Upvotes: 0

Mister Jojo
Mister Jojo

Reputation: 22365

you may use input event, which is also valid for any forms elements

demo:

const myForm = document.forms['my-form'];
  
myForm.addEventListener('submit', e => 
  {
  e.preventDefault(); // disable submit - page reload
  const formValues = Object.fromEntries(new FormData(myForm).entries());
  console.log( formValues );
  setTimeout(console.clear,3000);
  })

myForm.addEventListener('input', e => 
  {
  if (!e.target.matches('input[type="radio"]')) return;
  
  console.log(myForm['difficulty-ask'].value);
  setTimeout(console.clear,1300);
  });
label    { display: block; cursor: pointer; }
fieldset { width: fit-content; }
<form name="my-form">
  <fieldset>
    <legend> difficulty </legend>
    <label>
      <input name="difficulty-ask" type="radio" value="all" checked >
      All
    </label>
    <label>
      <input name="difficulty-ask" type="radio" value="easy" >
      Easy
    </label>
    <label>
      <input name="difficulty-ask" type="radio" value="medium" >
      Medium
    </label>
    <label>
      <input name="difficulty-ask" type="radio" value="hard" >
      Hard
    </label>
  </fieldset>
  <button>submit</button>
</form>

Upvotes: 1

Mehdi
Mehdi

Reputation: 1747

You can also use click or also change as you have 2 choices value. You can use event delegation combined with call() method. Here I added event delegation to input type radio only and also added an input type checkbox in HTML

const div = document.querySelector('div')
console.log(div)
div.addEventListener('change',(e)=>{
    let target = e.target
    if(target.matches("input[type='radio']")){
        check.call(e.target,e)
    }
})


function check(){
    console.log(this.value)
}
<div>
        <span>
          <input
            type="radio"
            id="all0"
            name="difficulty-ask"
            class="difficultyaskclass"
            value="all"
            checked="checked"
          />
          <label for="all0">All</label>
          <input
            type="radio"
            id="2easy1"
            name="difficulty-ask"
            class="difficultyaskclass"
            value="easy"
          />
          <label for="2easy1">Easy</label>
          <input
            type="radio"
            id="2med2"
            name="difficulty-ask"
            class="difficultyaskclass"
            value="medium"
          />
          <label for="2med2">Medium</label>
          <input
            type="radio"
            id="2hard3"
            name="difficulty-ask"
            class="difficultyaskclass"
            value="hard"
          />
          <label for="2hard3">Hard</label>
          <label for="2med45">checkbox</label>
          <input
            type="checkbox"
            id="2hard36"
            name="difficulty-ask1"
            class="difficultyaskclass5"
            value="hardtoveryhard"
          />
          <label for="2hard36">Hard</label>
        </span>
      </div>

Upvotes: 0

Related Questions