23

I have several radio buttons with the same name. Like this:

<form name="formA">
<input type="radio" name="myradio" value="A"/>
<input type="radio" name="myradio" value="B"/>
<input type="radio" name="myradio" value="C"/>
<input type="radio" name="myradio" value="D"/>
</form>

Now I have to add event listener through javascript to all the radio buttons. If the below pseudocode is wrong, then please tell me how to do it-

var radios = document.forms["formA"].elements["myradio"];
  for(radio in radios) {
    radio.onclick = function() {
        alert(radio.value);
    }
}
Acn
  • 1,010
  • 2
  • 11
  • 22

8 Answers8

23

For in loops in JavaScript return the keys, not the values. To get the for in loop to work, assuming you haven't added custom properties to your array, you'd do:

for(radio in radios) {
    radios[radio].onclick = function() {
        alert(this.value);
    }
}

But you should always loop an array with a regular for loop to avoid accidentally including custom-added enumerable properties:

var radios = document.forms["formA"].elements["myradio"];
for(var i = 0, max = radios.length; i < max; i++) {
    radios[i].onclick = function() {
        alert(this.value);
    }
}
Adam Rackis
  • 82,527
  • 56
  • 270
  • 393
  • Why should you "*always* loop an array with a regular for loop"? – ojrask Nov 03 '15 at 13:06
  • 1
    @ojrask - old answer, but basically custom-added properties, if added, could be iterated. But of course with ES6 now you have a `for of` loop you can use with arrays or any iterable. – Adam Rackis Nov 04 '15 at 20:42
  • 1
    Ah yes I see. Didn't think of that. Maybe edit the answer to elaborate on that? :) – ojrask Nov 04 '15 at 21:13
14

Another option is to attach multiple elements to a single event listener by using delegated handlers

You can attach the parent listener to document or any appropriate parent node. Then you can check the event was raised by the appropriate target using the Element.matches() API or anything on event.target

document.getElementById("languages").addEventListener('click', function (event) {
    if (event.target && event.target.matches("input[type='radio']")) {
        // do something here ...
    }
});

This is roughly equivalent to the following jQuery syntax which uses .on() to provide delegation

$("#languages").on("click", "input[type='radio']", function(event) {
    // do something here ...
});

If you want to extend the EventTarget.addEventListener() prototype, you can wrap with your own method:

window.EventTarget.prototype.addDelegatedListener = function(type, delegateSelector, listener) {
    this.addEventListener(type, function (event) {
        if (event.target && event.target.matches(delegateSelector)) {
            listener.call(event.target, event)
        }
    });
}

Then use like this:

document.addDelegatedListener("click", "input[type='radio']", function(event) {
    // do something here ...
});

Demo in Stack Snippets

// example 1 - regular add event listener
document.getElementById("languages").addEventListener('click', function (event) {
    if ( event.target && event.target.matches("input[type='radio']") ) {
        console.log(event.target.value)
    }
});

// example 2 - reusable delegated listener
window.EventTarget.prototype.addDelegatedListener = function(type, delegateSelector, listener) {
    this.addEventListener(type, function (event) {
        if (event.target && event.target.matches(delegateSelector)) {
            listener.call(event.target, event)
        }
    });
}

let parent = document.getElementById("weekdays")
parent.addDelegatedListener("click", "input[type='radio']", function(event) {
    console.log(this.value)
});
h3 {
    margin-top: 20px;
    margin-bottom: 10px;
    font-size: 1.1em;
}
code {
    background: #e9e9e9;
    padding: 1px 4px;
    border-radius: 3px;
}
label input {
    vertical-align: text-top;
}
<h3>Languages <code>addEventListener</code> + <code>Element.matches</code></h3>
<div id="languages">
  <label><input type="radio" name="languages" value="HTML"> HTML </label>
  <label><input type="radio" name="languages" value="JS"> JS </label>
  <label><input type="radio" name="languages" value="CSS"> CSS </label>
</div>

<h3>Weekdays <code>EventTarget.prototype.addDelegatedListener</code></h3>
<div id="weekdays">
  <label><input type="radio" name="days" value="Mon"> Mon </label>
  <label><input type="radio" name="days" value="Tue"> Tue </label>
  <label><input type="radio" name="days" value="Wed"> Wed </label>
</div>
KyleMit
  • 30,350
  • 66
  • 462
  • 664
  • I agree with suggesting the use of the [event delegation](https://javascript.info/event-delegation) pattern, but I don't agree with extending native built-ins with custom methods, for the same reasons that [this blog](https://web.archive.org/web/20220507220204/http://perfectionkills.com/extending-native-builtins/) suggests you shouldn't. Perhaps just creating a function to create delegated listeners without adding it to the `EventTarget.prototype` would be more future-proof, or creating a wrapper object to extend first, such as what jQuery returns when you `$()`. – ADJenks Sep 08 '22 at 16:34
8

You could add just a single listener that listens to all radio buttons, rather than individual listeners.

using jquery, you could do it like this

$(document).ready(function(){
    $('input[type=radio]').click(function(){
        alert(this.value);
    });
});

Demo

For only the radios within a form with id formA

 $(document).ready(function(){
        $('#formA input[type=radio]').click(function(){
            alert(this.value);
        });
    });

For only radios with an id myradio

$(document).ready(function(){
    $('input[type=radio]').click(function(){
        if (this.id == "myradio")
            alert(this.value);
    });
});

Demo

Ayush
  • 41,754
  • 51
  • 164
  • 239
  • 3
    1. I need pure javascript code. 2. I want to attach event listener to only those radios, which have the name attribute set to "myradio" (consider). But I think above code will attach the function to all radios in the entire document. :( – Acn Jan 19 '12 at 06:47
  • @BigFatPig you can have it attach only to the radios within that particular form, or even radios that have a particular id – Ayush Jan 19 '12 at 06:49
6

A good start, but don't use for..in that way as it will iterate over all enumerable properties and you haven't checked to see if they all represent elements.

Much better to use an index:

for (var i=0, iLen=radios.length; i<iLen; i++) {
  radios[i].onclick = function() {...};
} 
RobG
  • 142,382
  • 31
  • 172
  • 209
2

Try this :

var radioButtonSection = document.getElementsByName('eazi_auto_loan_option');

for (var i = 0; i < radioButtonSection.length; i++) {
        radioButtonSection[i].onclick = function() {
            console.log(this.value);
        }
    }
Mitchell van Zuylen
  • 3,905
  • 4
  • 27
  • 64
2
for(var property in object) { ... } 

is used to loop in objects to find properties. for array you can use normal for loop

for(var i=0; i< radios.length; i++) {
     var radio = radios[i];
     ....
} 
Diode
  • 24,570
  • 8
  • 40
  • 51
0

The most elegant solution:

Attach the listener to the FORM element. Then events will bubble up from the radio buttons to the form.

The following code assumes that you have only radio buttons in the form, like the example in the question.

If there are other input elements, maybe enclose the radio group in a span, then attach listener to the span.

let myForm = document.forms["formA"];
myForm.onchange = evt => console.log("Radio Checked:", evt.target.value);
Fitz
  • 1
0
for (let elem of document.querySelectorAll('input[type="radio"][name="myradio"]')) {
    elem.addEventListener("input", (event) => {  
        console.log(event.target.value);
    });
}
Donald Duck
  • 8,409
  • 22
  • 75
  • 99