1

I am trying to make a radio-button filter that changes its background color when it's selected. Right now it looks like this:

           <div data-bind="visible: applications().length > 0">
                            <label>Filter: </label>
                            <label class="radio-inline">
                                <input type="radio" value="new" data-bind="checked: applicationsFilter, css: {selected: applicationsFilter}" class="" />
                                New / Pending Review
                                (<span data-bind="text: newApplicationsCount"></span>)
                            </label>
                            <label class="radio-inline">
                                <input type="radio" value="shortlisted" data-bind="checked: applicationsFilter, css: {selected: applicationsFilter}" />
                                Shortlisted
                                (<span data-bind="text: shortlistedApplicationsCount"></span>)
                            </label>
                            <label class="radio-inline">
                                <input type="radio" value="connected" data-bind="checked: applicationsFilter, css: {selected: applicationsFilter}}" />
                                Connected
                                (<span data-bind="text: connectedApplicationsCount"></span>)
                            </label>
                            <label class="radio-inline">
                                <input type="radio" value="all" data-bind="checked: applicationsFilter, css: {selected: applicationsFilter}" />
                                All
                                (<span data-bind="text: allApplicationsCount"></span>)
                            </label>
                            <label class="radio-inline" data-bind="visible: applications().length > 0">
                                <input type="checkbox" data-bind="checked: showHiddenApplications" />
                                Include Hidden
                            </label>
                        </div>

My intention was to apply the .selected class when the radio-button is selected by doing

 data-bind="checked: applicationsFilter, css: {selected: applicationsFilter}}

But the output does not actually apply the css style. What is the proper way of doing this?

Thanks

Dukakus17
  • 1,221
  • 4
  • 15
  • 32

1 Answers1

3

The correct way to do this is by making an actual comparison that evaluates to true or false:

css: {selected: applicationsFilter() == 'new'}

But you might also run into the issue that - especially Firefox, but other browsers as well - ignore styles on radio buttons.

One option would be to use the css binding on the label instead of the input.

Another would be to make separate inputs+labels, instead of nested ones, and use CSS to react to the :checked state. The following uses the very helpful uniqueId and uniqueFor custom bindings by RP Niemeyer.

// uniqueId/uniqeFor custom bindings by @RPNiemeyer, https://stackoverflow.com/a/9235013/18771
ko.bindingHandlers.uniqueId = {
    init: function(element, valueAccessor) {
        var value = valueAccessor();
        value.id = value.id || ko.bindingHandlers.uniqueId.prefix + (++ko.bindingHandlers.uniqueId.counter);

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

ko.bindingHandlers.uniqueFor = {
    init: function(element, valueAccessor) {
        var value = valueAccessor();
        value.id = value.id || ko.bindingHandlers.uniqueId.prefix + (++ko.bindingHandlers.uniqueId.counter);

        element.setAttribute("for", value.id);
    } 
};


ko.applyBindings({
    applicationsFilter: ko.observable(),
    filterOptions: [
        {value: "new", label: "New / Pending Review"},
        {value: "shortlisted", label: "Shortlisted"},
        {value: "connected", label: "Connected"},
        {value: "all", label: "All"},
    ]
});
.radio-inline:checked+label {
    border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<div data-bind="foreach: filterOptions">
    <input type="radio" class="radio-inline" data-bind="value: value, checked: $parent.applicationsFilter, uniqueId: $data" />
    <label data-bind="text: label, uniqueFor: $data"></label>
</div>

<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
Tomalak
  • 332,285
  • 67
  • 532
  • 628