Tom W Hall
Tom W Hall

Reputation: 5283

Knockout.js unique IDs for use in "for" label attribute in radio button groups

I've implemented a variant of the very cunning answer here for generating unique IDs for inputs and corresponding labels in my Knockout markup. My end goal is clickable labels, not unique IDs per se - I had previously been using a click binding on each label which navigated the DOM to select its input, but that seemed breaky and inefficient.

However the solution linked doesn't work for radio button groups where each radio in the group binds back to the same observable. In my case my radio groups are either true / false (binding back to a boolean observable) or represent an enum, in which case the observable holds an integer value. The solution as provided results in all of the radios in a group (and their corresponding label for attributes) getting the same ID.

To make matters more complex, these radio button sets themselves appear multiple times. For example, there might be 10 templated divs each with a set of 3 radio buttons: Red, Green, Blue - each radio having a label which I want to activate the corresponding radio on click.

I've been struggling to modify this solution to suit, but my brain has now locked up. Any ideas welcome!

Upvotes: 4

Views: 6454

Answers (1)

Kyeotic
Kyeotic

Reputation: 19857

From my comment, a fiddle using RP's binding with a modification

ko.bindingHandlers.uniqueId = {
    init: function(element, valueAccessor, allBindingsAccessor) {
        var value = valueAccessor();
        var idMod = 'id-' + (allBindingsAccessor().uniqueMod || 0);
        value[idMod] = value[idMod] || ko.bindingHandlers.uniqueId.prefix + (++ko.bindingHandlers.uniqueId.counter);

        element.id= value[idMod];
    },
    counter: 0,
    prefix: "unique"
};

ko.bindingHandlers.uniqueFor = {
    init: function(element, valueAccessor, allBindingsAccessor) {
        var value = valueAccessor();
        var idMod = 'id-' + (allBindingsAccessor().uniqueMod || 0);
        value[idMod] = value[idMod] || ko.bindingHandlers.uniqueId.prefix + (++ko.bindingHandlers.uniqueId.counter);

        element.setAttribute("for", value[idMod]);
    } 
};

Example use:

<input type="radio" data-bind="checked: gender, attr: { name: 'gender-' + id() },
     uniqueId: gender, uniqueMod: 'male'" value="1" />
<label data-bind="uniqueFor: gender, uniqueMod: 'male' ">Male</label>

<input type="radio" data-bind="checked: gender, attr: { name: 'gender-' + id() },
    uniqueId: gender, uniqueMod: 'female'" value="2" />
<label data-bind="uniqueFor: gender, uniqueMod: 'female '">Female</label>

Upvotes: 8

Related Questions