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>
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>
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With