Guto
Guto

Reputation: 341

Change value of a Radio Button when another is clicked

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

Answers (2)

Derpy
Derpy

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

Rohith Nair
Rohith Nair

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

Related Questions