Saturday, 12 August 2017

knockout.js - Knockout + Radiobuttons - getting the value to toggle back to 'false' on uncheck



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

casting - Why wasn't Tobey Maguire in The Amazing Spider-Man? - Movies & TV

In the Spider-Man franchise, Tobey Maguire is an outstanding performer as a Spider-Man and also reprised his role in the sequels Spider-Man...