I have a Knockout app, where I have multiple boolean properties and only 1 can be true. (Rather than 1 underlying property, with each radiobutton being a distinct value).
When I select a radio button, the observable will correctly update to the radio button's checkedValue. When I de-select it, the value remains. Is there any way I can have this set the observable to false?
My JS fiddle example: http://jsfiddle.net/9mu8e/
I'm a little wary of setting an intermediate value, and .subscribe() to sort out all values. (And the scattered booleans is a feature of the REST interface we're sending to).
Update: I've added the 'Add new' button to show the list as being dynamic, and possibly containing duplicate values (so tracking against the text property, or a theoretical DB ID isn't possible). jsFiddle link is updated.
My example:
View:
Current item:
View Model:
var item = function(name, dbId) {
var self = this;
self.dbId = ko.observable(dbId);
self.name = ko.observable(name);
self.isMostTerrible = ko.observable(false);
}
var itemList = [
new item("Taxes", 1),
new item("Death", 2)
]
var viewModel = function() {
var self = this;
self.isMostTerrible = ko.observable(true);
self.itemsList = ko.observableArray(itemList);
self.onAddNewItem = function() {
// Note - Adding a new item doesn't add a DB ID.
// (Theoretically occurs on save)
self.itemsList.push(new item("New item"));
}
};
ko.applyBindings(viewModel);
Answer
One problem is that Knockout's checked binding simply doesn't work the way you're trying to use it. It's meant to be set up with a single observable that is bound to all radio buttons in the group, with each button having a unique value.
Another problem is that the browser doesn't provide a notification when a radio button is de-selected. (See OnChange event handler for radio button (INPUT type="radio") doesn't work as one value). So a simple binding that listens for the change event won't work.
Still, what you want is possible using a custom binding. The one I've included below uses an observable to keep track of the currently selected radio button so that it can update the model values accordingly.
ko.bindingHandlers.radioChecked = (function() {
var groupObservables = {};
return {
init: function(element, valueAccessor) {
var name = element.name,
groupObservable = groupObservables[name] || (groupObservables[name] = ko.observable());
ko.utils.registerEventHandler(element, 'click', function() {
valueAccessor()(element.checked);
});
var s1 = ko.computed(function() {
if (valueAccessor()()) {
element.checked = true;
groupObservable(element);
}
});
var s2 = groupObservable.subscribe(function() {
valueAccessor()(element.checked);
});
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
s1.dispose();
s2.dispose();
});
}
};
})();
Fiddle: http://jsfiddle.net/mbest/3dy3s/
No comments:
Post a Comment