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