Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I detect a change in value of a RadioNodeList?

Tags:

javascript

With a form my_form with a set of radio buttons with name=my_radio I can get a RadioNodeList object with my_form.elements.my_radio. I can get the value of the currently selected button with that object's value property, and if I assign a string to the value property the selected option changes as appropriate.

I expected to be able to do my_form.elements.my_radio.addEventListener('change', ..., to listen for the value changing (via the user selecting a different option) but it has no such method.

How can I detect the value changing?

Is the only way to set up event listeners on each individual radio button object?

var my_form = document.querySelector('#my_form');
var my_radio = my_form.elements.my_radio;

// This fails since RadioNodeList has no addEventListener function
/*
my_radio.addEventListener('change', function () {
console.log("Value changed; new value is " + my_radio.value);
});
*/

// The following works, but is there a better way, such as with a single event listener?
for (var i = 0, l = my_radio.length; i < l; i++) {
my_radio[i].addEventListener('change', function () {
	console.log("Value changed; new value is " + my_radio.value);
});
}
<form id=my_form>
<div>
	<label>
		<input type=radio name=my_radio value=value_1>
		Value 1
	</label>
</div>
<div>
	<label>
		<input type=radio name=my_radio value=value_2>
		Value 2
	</label>
</div>
<div>
	<label>
		<input type=radio name=my_radio value=value_3>
		Value 3
	</label>
</div>
<div>
	<label>
		Some other field where I don't need to detect changes
		<input name=some_other_field>
	</label>
</div>
</form>
like image 453
tremby Avatar asked Nov 08 '22 10:11

tremby


1 Answers

In your markup, wrap just the radio buttons in a fieldset. Then attach the event-listener to that instead of the form, so it won't fire for changes to other <input> fields.

Here is the modified code:

var my_form = document.querySelector('#my_form');
var my_radio = my_form.elements.my_radio;
var my_radio_group = document.querySelector('#my_radio_group');

// Attach the eventListener to the fieldset instead of the form
my_radio_group.addEventListener('change', function() {
  // You actually don't even need the other global variables; this also works:
  // let my_radio = this.form.elements.my_radio);
  console.log("Value changed; new value is " + my_radio.value);  
});
/* If you don't want any border around the radio group */
#my_radio_group {
  border: none;
}
<form id="my_form">
  <fieldset id="my_radio_group">
    <div>
      <label>
        <input type="radio" name="my_radio" value="value_1">
        Value 1
      </label>
    </div>
    <div>
      <label>
        <input type="radio" name="my_radio" value="value_2">
        Value 2
      </label>
    </div>
    <div>
      <label>
        <input type="radio" name="my_radio" value="value_3">
        Value 3
      </label>
    </div>
  </fieldset>

  <div>
    <label>
      Some other field where I don't need to detect changes
      <input name="some_other_field">
     </label>
  </div>
</form>

Why OP's first approach fails

A RadioNodeList, being a kind of NodeList, is a collection of Nodes (radio elements in this case). As such, it is much like a JS Array (you can do my_radio[i]). In JS, Events can be received only by objects that inherit the EventTarget interface, like Nodes and HTML Elements, and not by collections like arrays and NodeLists.

To attach a single event handler for multiple elements, you have to attach it to a close parent and use Event Delegation. Which is what I did in my solution, using the <fieldset> element. Any wrapper element e.g. <div> would have sufficed; only that the <fieldset> is semantically more accurate here.

like image 191
Shiva Prasad Avatar answered Nov 14 '22 22:11

Shiva Prasad