A label tag wrapped around a radio button prevents the radio button from responding to a "change" event listener in JavaScript

StackOverflow https://stackoverflow.com/questions/23304287

Question

Problem

I have some dynamically generated HTML (using JavaScript) that contains a form with some radio buttons in it. I added event listeners (using "change") to all of the radio buttons to call a function whenever their value is changed. I am already aware that this event only triggers when a button's "checked" value goes from false to true, and not the other way around.

To simplify my code, I've wrapped the label tags around the input tags to avoid having to generate a bunch of unique id's for my radio buttons. However, when the label tags are wrapped around the radio inputs rather than sitting in the same scope as the radio inputs, the "change" event listener does not respond, even when clicking directly on the button itself.

Examples

I put together a jsfiddle example to show what I'm talking about. JS Fiddle Example The first group (that doesn't work) is generated this way:

for (var i = 0; i < 3; i++)
{
    var label = document.createElement("label");
    var radio = document.createElement("input");
    radio.setAttribute("type", "radio");
    radio.setAttribute("name", "group1");

    radio.addEventListener("change", function()
    {
        alert("group1 changed!")
    }, false);

    label.appendChild(radio);
    label.innerHTML += "Radio " + (i + 1);
    var br = document.createElement("br");
    g1.appendChild(label);
    g1.appendChild(br);
}

And the second group (that does work) is generated this way:

for (var i = 0; i < 3; i++)
{
    var radio = document.createElement("input");
    radio.setAttribute("type", "radio");
    radio.setAttribute("name", "group2");
    radio.setAttribute("id", "g2r" + i);

    radio.addEventListener("change", function()
    {
        alert("group2 changed!")
    }, false);

    var label = document.createElement("label");
    label.setAttribute("for", "g2r" + i);
    label.innerHTML = "Radio " + (i + 1);
    var br = document.createElement("br");
    g2.appendChild(radio);
    g2.appendChild(label);
    g2.appendChild(br);
}

Question

Is this an known bug or something? And is there some kind of workaround? I'd like to keep the wrapped labels because it's easier to generate, and I think it's cleaner, but not at the expense of functionality, obviously.

Thank you!

Was it helpful?

Solution

I removed the line:

    label.innerHTML += "Radio " + (i + 1);

from your jsFiddle and that fixes the issue. The reason this is breaking your code is that when you use innerHTML to add something to inside another element, what you're really doing is replacing all of the contents of that element. Sure, when you use += you're keeping what was there before and adding to it, but you're still essentially copying the contents out, adding to them, and then creating NEW DOM ELEMENTS for all the html you're adding back in -- whether it's the old contents or the new. This means that any handlers bound to the old contents will be lost, since you're overwriting them with new DOM elements.

If you replace that line with this:

    label.appendChild(document.createTextNode("Radio " + (i + 1)));

That'll append the new text node you're creating without removing and recreating any of your existing elements, so your handlers will still be there! Here's a working jsFiddle: http://jsfiddle.net/335cQ/13/.

OTHER TIPS

radio.setAttribute("id", "rb");

<style>
#rb
{
    z-index:5;
}
</style>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top