Reputation: 341
I need to create a list of options that when I click in one option I change the value off all other option with "X". It's working fine except that the option that I select do not stay selected. Does anyone know what is wrong?
var data = [{
name: "CheckBox1",
status: " "
}, {
name: "CheckBox2",
status: "X"
}, {
name: "CheckBox3",
status: "X"
}];
var ViewModel = function() {
var self = this;
self.list = ko.mapping.fromJS(data);
self.change = function(data) {
for (i = 0; i < self.list().length; i++)
self.list()[i].status("X");
data.status(" ");
return true;
}
}
ko.applyBindings(new ViewModel(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<!--ko foreach: $root.list-->
<!-- ko with: $data -->
<label data-bind="text: name"></label>
<input type="radio" data-bind="checkedValue: status() === ' ', click:$root.change" />
<!--/ko-->
<!--/ko-->
<!--ko foreach: $root.list-->
<!-- ko with: $data -->
<p data-bind="text: name"></p>
<p data-bind="text: status"></p>
<!--/ko-->
<!--/ko-->
Upvotes: 0
Views: 3362
Reputation: 1528
If you redo the way you bind the radio buttons (like on the knockout website), you don't have to manually update the checked values. Since your checked binding is a boolean expression, the checked binding is effectively a one-way binding instead of a two-way binding. The data will drive the interface, but the interface won't drive the data. This is why you have to manually 'check' the boxes in the click function. That said, in the interest of minimally modifying your example I was able to get it working with a few tweaks.
Edit: Realizing now that while this make the sample "work" it just breaks the checked binding. So... if you were to update the data, it would not drive the controls.
Remove the invoke parenthesis in the checked binding. This was part of the reason the radio buttons weren't updating after the data was updated.
<input type="radio" name="optradio" data-bind="checked: status == ' ', click: $root.change" />
Modify the values of the collection to which the controls are bound, not the incoming data parameter. If you don't modify the collection directly, you don't update the object the control is referencing. It's basically like a pass by value vs pass by reference thing.
for (i = 0; i < self.list().length; i++){
if(self.list()[i].name() == data.name()){
self.list()[i].status(' ');
}
else{
self.list()[i].status('X')
}
}
var data = [{
name: "CheckBox1",
status: " "
}, {
name: "CheckBox2",
status: "X"
}, {
name: "CheckBox3",
status: "X"
}];
var ViewModel = function() {
var self = this;
self.list = ko.mapping.fromJS(data);
self.change = function(data) {
for (i = 0; i < self.list().length; i++){
if(self.list()[i].name() == data.name()){
self.list()[i].status(' ');
}
else{
self.list()[i].status('X')
}
}
for (i = 0; i < self.list().length; i++)
alert(self.list()[i].status());
return true;
}
}
ko.applyBindings(new ViewModel(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<!--ko foreach: $root.list-->
<!-- ko with: $data -->
<label data-bind="text: name"></label>
<input type="radio" name="optradio" data-bind="checked: status === ' ', click:$root.change" />
<!--/ko-->
<!--/ko-->
Upvotes: 1
Reputation: 1070
https://jsfiddle.net/ptk2jf8v/20/
<input type="radio" name="optradio" data-bind="checkedValue: status() === ' ', click:$root.change,value:status" />
and returning true from click handler will do the trick
From :http://knockoutjs.com/documentation/checked-binding.html
If your binding also includes checkedValue, this defines the value used by the checked binding instead of the element’s value attribute. This is useful if you want the value to be something other than a string (such as an integer or object), or you want the value set dynamically.
In your case you are marking as checked when status is empty.
And also the click event is messing up with the default action happening on radio button.
From knockout js radio button click event reset selection
By default, Knockout will prevent the click event from taking any default action
So returning true from click event will help the bubbling.
Upvotes: 1