Knockout radio button binding with boolean

那年仲夏 提交于 2019-12-23 02:39:14

问题


As per this Fiddle I created when you run it it does not bind the value to "no Blue" option as expected.

var viewModel = {    
    isBlue: ko.observable(false)
    //isBlue: ko.observable("false") this works
};

As I have mentioned in there when I pass a string value "false" it does the binding. It's clear that knockout does type comparison as well.

In my application I am using komapper which creates the view model. For properties in boolean it creates bool values and initialises variables in bool. Do I need to convert them to strings? In input radio button element we will always have to work with string values. Can I use a boolean value for checkboxes?

I tried with "checkedValue" still no luck.


回答1:


I think you're experiencing a bug that has been fixed in a later version of knockout.

The way it should work (and like you tried):

<input name="Test" type="radio" data-bind="checkedValue: true, 
                                           checked: isBlue" />Blue
<input name="Test" type="radio" data-bind="checkedValue: false, 
                                           checked: isBlue" />No Blue
ko.applyBindings({
  isBlue: ko.observable(false)
});

If you include knockout version 3.4, it works as expected:

ko.applyBindings({
  isBlue: ko.observable(false)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>

<label>
  <input name="Test" type="radio" data-bind="checkedValue: true, checked: isBlue" /> Blue
</label>
<label>
  <input name="Test" type="radio" data-bind="checkedValue: false, checked: isBlue" /> No Blue
</label>
<br />
<strong style="color: green">3.4.0: Does work</strong>

When you include the version you've used in the fiddle (2.1.0), it doesn't:

ko.applyBindings({
  isBlue: ko.observable(false)
});
<script src="https://cloud.github.com/downloads/knockout/knockout/knockout-2.1.0.js"></script>

<label>
  <input name="Test" type="radio" data-bind="checkedValue: true, checked: isBlue" />Blue
</label>
<label>
  <input name="Test" type="radio" data-bind="checkedValue: false, checked: isBlue" />No Blue
</label>
<br />
<strong style="color: red">2.1.0: Does not work</strong>

Edit: after some more digging: I don't think it's a bug in 2.1.0; the checkedValue didn't even exist at that point!

Looking at the source you notice the logic for getting the checked value is very different between 2.1.0 and later versions:

In 2.1.0:

if (element.type == "checkbox") {
  valueToWrite = element.checked;
} else if ((element.type == "radio") && (element.checked)) {
  valueToWrite = element.value;
}

In 3.4.0:

 var checkedValue = ko.pureComputed(function() {
   // Treat "value" like "checkedValue" when it is included with "checked" binding
   if (allBindings['has']('checkedValue')) {
     return ko.utils.unwrapObservable(allBindings.get('checkedValue'));
   } else if (allBindings['has']('value')) {
     return ko.utils.unwrapObservable(allBindings.get('value'));
   }

  return element.value;
});

So a definite answer would be: update to 3.4.0, or create a custom checked binding that implements the 3.4.0 behavior (if a version update would break your project)




回答2:


Aye. The src binding internally just returns element.value, which for the browser is a string. Check the source file, with this abbreviated/annotated code for getting value associated with being checked:

var checkedValue = ko.pureComputed(function() {
    // Abbreviated, first KO does some stuff for other cases, but
    // in the end it'll do:

    return element.value; // Where `element` is the actual DOM element.
});

Typically, a boolean value would be represented by a checkbox, where you only experience your issue in half of the cases (in which you'd need something like "an inverse checked binding").

Solutions include the one you mention (using strings) as well as using a writeable computed fronting the actual observable, e.g.:

viewModel.viewIsBlue = ko.computed({
  read: function() { return viewModel.isBlue().toLocaleString(); },
  write: function(newVal) { viewModel.isBlue(newVal === 'true'); }
});

You could also possibly go to work with a custom extender with similar functionality if you find yourself repeating the above too often.



来源:https://stackoverflow.com/questions/38606419/knockout-radio-button-binding-with-boolean

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!