stevenspiel
stevenspiel

Reputation: 6019

Pure Javascript target label

I have some checkboxes and I want the text of the label to change when the checkbox is selected:

JSFIDDLE

var listener = function() {
    document.addEventListener('change', function(e) {
            if (e.target.checked) {
                e.target.label.className = "option-selected";
            }
        }
    }
}

HTML if you are interested:

<input id="0A" class="individual-checkbox" type="checkbox" value="A">
<label for="0A">A</label>
<br>
<input id="0B" class="individual-checkbox" type="checkbox" value="B">
<label for="0B">B</label>

Obviously, target.label doesn't work. How do I access the label of the target and give it a CSS class (purely in JavaScript)?

Upvotes: 0

Views: 10525

Answers (3)

jko
jko

Reputation: 2098

this will do the trick:

function addListener(elem) {
    // remember: checkboxes never change trair value 
    elem.addEventListener('click', function () {
        var ls = document.getElementsByTagName('label');
        for (var l = 0, ll = ls.length, lbl; l < ll; ++l) {
            lbl = ls[l];
            if ( this.id == lbl.getAttribute("for") )
            {
                lbl.className = ( this.checked ? "option-selected" : "" );
            }
        }
    });
}

see http://jsfiddle.net/fGSCH/10/

be aware that addListener() might not work in every browser. but since you used it in the example i will use it too.

Upvotes: 0

jfriend00
jfriend00

Reputation: 708146

To make your jsFiddle work, you have to change the following:

  1. Fix the syntax error (missing a closing paren for the addListener() function call and you have an extra closing brace.
  2. Actually call the listener() function to make it run.
  3. Target the actual label, not the checkbox with your class

There are several different ways to target the label. The simplest would be to enclose the input inside the label and then just use .parentNode to get the label from the checkbox.

HTML:

<label for="0A">
    <input id="0A" class="individual-checkbox" type="checkbox" value="A">
A</label>
<br>
<label for="0B">
    <input id="0B" class="individual-checkbox" type="checkbox" value="B">
B</label>

code:

var listener = function() {
    document.addEventListener('change', function(e) {
        if (e.target.checked) {
            e.target.parentNode.className = "option-selected";
        }
    });
}
listener();

Working jsFiddle: http://jsfiddle.net/jfriend00/s2A7W/


If you don't want to change your HTML, then you just need to find the label element that is right after your input element.

You can do that like this:

var listener = function() {
    document.addEventListener('change', function(e) {
        var label;
        if (e.target.checked) {
            label = next(e.target, "label");
            if (label) {
                label.className = "option-selected";
            }
        }
    });
}
listener();

function next(src, tag) {
    tag = tag.toUpperCase();
    while (src && src.tagName !== tag) {
        src = src.nextSibling;
    }
    return src;    
}

Working jsFiddle: http://jsfiddle.net/jfriend00/3wQKa/


FYI, you should probably also restrict the action of your listener to only when a checkbox is actually the target or an element with a particular classname or some other distinguishing feature that makes sure it's a checkbox you want targeted by this code. You are probably safe with e.target.checked, but I don't like the fact that this event listener responds to all propagated change events in the entire page.

Upvotes: 3

Felix Kling
Felix Kling

Reputation: 817208

Assuming there is only one label element associated with the element:

e.target.labels[0].className = "option-selected";

This is an HTML5 property though, I don't know how well it is supported in older browsers. Source: MDN.

Alternatively, if IE8 support is enough for you, you can explicitly search for it with document.querySelector:

var label = document.querySelector('[for=' + e.target.name + ']');

This only works if you give the input elements name attributes (which you really want to do, otherwise the labels are not properly connected to the input elements).

And finally, if the label always comes after the input, you can traverse the DOM:

var label = e.target.nextSibling;
while (label.nodeName !== 'LABEL') {
    label = label.nextSibling;
}

If you'd restructure your HTML so that the input element is a child of the label element:

<label for="0A">
    <input id="0A" class="individual-checkbox" type="checkbox" value="A">
    A
</label>

then you could simply use e.target.parentNode to get the label. Putting the input element inside the label also connects the label to the input.

Upvotes: 1

Related Questions