I have a case when I need to bind a checkbox and the visibility of another DOM element to the inverse of a boolean property of my viewModel:
<input type="checkbox" data-bind="checked: needsReview"> Not Required
<br>
<div id="Some related text" data-bind="visible: needsReview"> other stuff here </div>
var dataFromSever = { needsReview: true };
var theModel = function (jsonData) {
var self = this;
ko.mapping.fromJS(jsonData, {}, self);
}
ko.applyBindings(new theModel(dataFromSever));
I have more than one property like this in my actual data model, so I do not want to make multiple ko.computed()
fields. I'd just like to bind to "checked: !needsReview()"
or something equally simple to maintain.
There are a few similar ways to handle this one. The basic idea is that you need to create a writeable computed observable to bind the checkbox against.
You could do this in your model directly, using an extender, or by adding a function to the observable base (ko.observable.fn).
However, since you are using the mapping plugin and likely don't want to customize the way that your objects are created or add additional properties, I think that using a custom binding is the best option. Your model really does not need to be concerned with maintaining an inverse to your property, so we can actually do this part while binding.
Here is an inverseChecked
binding that inserts a writeable computed observable between your real observable and the binding. Then, it simply uses the real checked binding to do its work.
ko.bindingHandlers.inverseChecked = {
init: function(element, valueAccessor, allBindingsAccessor) {
var value = valueAccessor();
var interceptor = ko.computed({
read: function() {
return !value();
},
write: function(newValue) {
value(!newValue);
},
disposeWhenNodeIsRemoved: element
});
var newValueAccessor = function() { return interceptor; };
//keep a reference, so we can use in update function
ko.utils.domData.set(element, "newValueAccessor", newValueAccessor);
//call the real checked binding's init with the interceptor instead of our real observable
ko.bindingHandlers.checked.init(element, newValueAccessor, allBindingsAccessor);
},
update: function(element, valueAccessor) {
//call the real checked binding's update with our interceptor instead of our real observable
ko.bindingHandlers.checked.update(element, ko.utils.domData.get(element, "newValueAccessor"));
}
};
Here is a sample: http://jsfiddle.net/rniemeyer/Kz4Tf/
For your visible
binding you can do visible: !needsReview()
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