How to bind a flag to the opposite value?

I have a case where I need to bind the checkbox and visibility of another DOM element to the inverse logical 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)); 

In my real data model, I have several properties, so I do not want to create multiple ko.computed() fields. I would just like to get attached to "checked: !needsReview()" or something equally easy to maintain.

+4
source share
3 answers

There are several similar ways to handle this. The basic idea is that you need to create a writable computable observable in order to bind a checkbox.

You can do this directly in your model, using the expander or adding a function to the observed base (ko.observable.fn).

However, since you are using the mapping plugin and probably do not want to customize the way you create your objects or add additional properties, I think using custom bindings is the best option. Your model really does not have to care about maintaining the opposite of your property, so we can actually complete this part when binding.

Here is an inverseChecked binding that inserts a recordable calculated observable between your real observable and the binding. Then he simply uses real test binding to do his job.

 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 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 update with our interceptor instead of our real observable ko.bindingHandlers.checked.update(element, ko.utils.domData.get(element, "newValueAccessor")); } }; 

Here is an example: http://jsfiddle.net/rniemeyer/Kz4Tf/

For your binding visible you can make visible: !needsReview()

+12
source

I usually make my own bindHandler in KO, which is the inverse of visible :

 ko.bindingHandlers['invisible'] = { update: function(element, valueAccessor){ var val = ko.utils.unwrapObservable(valueAccessor()); ko.bindingHandlers['visible'].update(element, function() { return !val; }); } } 

This allows you to take care of the needs as you described, without cluttering your data-bind statements with ugly !val()

+2
source

I prefer a more general and universal way to invert the observed / calculated value (which does not depend on any particular binding):

 /** * A small handy observable / computed function that wraps around the inverse of it boolean value. * @author Nir Azuelos * @returns {Function} */ ko.observable.fn.inverse = ko.computed.fn.inverse = function() { return ko.pureComputed(function() { return !this(); }, this); }; 

Using:

 <div data-bind="visible: myObservable.inverse()"> 
0
source

Source: https://habr.com/ru/post/1391548/


All Articles