Search code examples
knockout.jsknockout-2.0knockout-mvc

How can I bind an editable ko.observableArray of observable strings?


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>

Solution

  • 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());