This is a follow-up to How can I bind a ko.observableArray of strings?
How can I bind an editable observable array of observable strings to a set of input boxes? I don't want to bind to an array of objects, as my underlying JSON sent from the server is an array of strings.
The following example doesn't work (try it at http://jsfiddle.net/LDNeA/). Binding an array of objects with observable strings is OK, but binding the array of observable strings directly doesn't work, and the model is not updated.
The important thing is that the entries in the textboxes are mapped back into the model.
JS:
var ViewModel = function() {
this.value = ko.observable("hi")
this.array1 = ko.observableArray([ko.observable("hi"), ko.observable("there")]);
this.array2 = ko.observableArray([{ data: ko.observable("hi") }, { data: ko.observable("there") }]);
};
ko.applyBindings(new ViewModel());
HTML:
<div class='liveExample'>
<p><input data-bind='value: value' /></p>
<div data-bind="foreach: array1">
<p><input data-bind='value: $data' /></p>
</div>
<div data-bind="foreach: array2">
<p><input data-bind='value: data' /></p>
</div>
</div>
<pre data-bind="text: ko.toJSON($data)"></pre>
To create an observable, assign the ko. observable function to the variable. A default value can be specified in the constructor of the call. Knockout then converts your variable into a function and tracks when the value changes, in order to notify the UI elements associated with the variable.
An observable is useful in various scenarios where we are displaying or editing multiple values and require repeated sections of the UI to appear and disappear as items are inserted and deleted. The main advantage of KO is that it updates our UI automatically when the view model changes.
As noted by links posted by @Tyrsius, this is a bug (?) in Knockout.
The easiest workaround is to use $parent.items()[$index()]
, as seen in this fiddle: http://jsfiddle.net/r8fSg/. Note that $parent.items()
is the observableArray of items that is used in the foreach.
<div data-bind="foreach: items">
<p><input data-bind='value: $parent.items()[$index()]' /></p>
</div>
<pre data-bind="text: ko.toJSON($data)"></pre>
And the model:
var ViewModel = function() {
this.items = ko.observableArray([ko.observable("hi"), ko.observable("hi")]);
};
ko.applyBindings(new ViewModel());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With