I'm trying to make use of the checkedValue binding introduced in knockout version 3, with radio buttons , but am not getting the behavior I expect.
Here's an example: (the viewModel has two properties; list is an array; checkedVal is an observable)
<div data-bind="foreach:list">
    <input type="radio" data-bind="
        checkedValue: {
            data: $data,
            index: $index(),
        },
        checked: $parent.checkedVal
    "/>
    <span data-bind="text: $data"></span>
</div>
JSFiddle
I expect the radio buttons to behave normally, and checkedVal to be an object containing the data and index. checkedVal is as I expect, but the radio buttons don't select. Oddly, in my actual code the behavior is inconsistent; sometimes the radio butttons work and sometimes they don't, but it consistently doesn't work in the fiddle, as far as I can see.
Is this a bug, or am I misunderstanding how this should be working?
Your checkedValue binding becomes a function as follows:
function () {
    return {
        data: $data,
        index: $index(),
    };
}
Each time the checked binding updates, it calls this function to get the value. But the function always returns a new object. Even though the objects contains the same data, Knockout doesn't see them as the same.
You can solve this by making the value a string.
    <input type="radio" data-bind="
        checkedValue: JSON.stringify({
            data: $data,
            index: $index(),
        }),
        checked: $parent.checkedVal
    "/>
Or by binding to a consistent value.
    <input type="radio" data-bind="
        checkedValue: $data,
        checked: $parent.checkedVal
    "/>
EDIT:
You can use a custom binding that follows the same pattern as checked, but allows for a comparison function.
ko.bindingHandlers.radioChecked = {
    init: function (element, valueAccessor, allBindings) {
        ko.utils.registerEventHandler(element, "click", function() {
            if (element.checked) {
                var observable = valueAccessor(), 
                    checkedValue =  allBindings.get('checkedValue');
                observable(checkedValue);
            }
        });
    },
    update: function (element, valueAccessor, allBindings) {
        var modelValue = valueAccessor()(), 
            checkedValue =  allBindings.get('checkedValue'), 
            comparer = allBindings.get('checkedComparer');
        element.checked = comparer(modelValue, checkedValue);
    }
};
Then objects can be compared by contents.
this.itemCompare = function(a, b) {
    return JSON.stringify(a) == JSON.stringify(b);
}
jsFiddle: http://jsfiddle.net/mbest/Q4LSQ/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With