Radio input knockout observable Array loses control after splicing
Enter radio input inside element multiplied by foreach knockout .
Give the observable array to this foreach.
Make a function to switch two of these items.
HTML:
<!-- ko foreach: boxes -->
<div>
<!-- ko text: $data --><!-- /ko -->:
<label><input type=radio value=apple data-bind="attr: { name: 'fruit-' + $index() }">apple</label>
<label><input type=radio value=banana data-bind="attr: { name: 'fruit-' + $index() }">banana</label>
</div>
<!-- /ko -->
<button data-bind="click: switchBoxes">switch</button>
JS:
var viewModel = function () {
this.boxes = ko.observableArray(['First', 'Second']);
this.switchBoxes = function () {
this.boxes.splice(0, 2, this.boxes()[1], this.boxes()[0]);
};
};
ko.applyBindings(new viewModel());
script: https://jsfiddle.net/hejdav/6dzg9hs8/17/
Now - check both radios, then switch. See? One of the radio stations loses its validation.
Any idea to prevent this?
One strange thing: the loss only occurs when both radios are checked.
source to share
Since you haven't bound a property checked
, the checked state is irrelevant to Knockout. I thought that simple observation and binding checked
would make Knockout keep everything in shape. Not so: you seem to have found a bug.
For some reason, Knockout doesn't set the new last item in the list correctly. I was able to fix this by adding a call valueHasMutated
to the checked
-bound observable for the last item in the blocks.
var viewModel = function() {
this.boxes = ko.observableArray([{
name: 'First',
value: ko.observable('')
}, {
name: 'Second',
value: ko.observable('')
}]);
this.switchBoxes = function() {
const arr = this.boxes();
this.boxes.splice(0, 2, arr[1], arr[0]);
arr[1].value.valueHasMutated();
};
};
ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<!-- ko foreach: boxes -->
<div>
<!-- ko text: name -->
<!-- /ko -->
(
<!-- ko text: value -->
<!-- /ko -->):
<label><input type=radio value=apple data-bind="attr: { name: 'fruit-' + $index() }, checked: value">apple</label>
<label><input type=radio value=banana data-bind="attr: { name: 'fruit-' + $index() }, checked: value">banana</label>
</div>
<!-- /ko -->
<button data-bind="click: switchBoxes">switch</button>
source to share