How to associate editable ko.observableArray with observable strings?

This is a sequel. How can I bind ko.observableArray strings?

How to associate an editable observable array of observable rows with a set of input fields? I don't want to bind to an array of objects, since my base JSON sent from the server is an array of strings.

The following example does not work (try http://jsfiddle.net/LDNeA/ ). Associating an array of objects with observed rows is fine, but binding an array of observed rows does not work directly, and the model is not updated.

The important thing is that the entries in the text boxes are mapped back to 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> 
+6
source share
4 answers

The problem is that Knockout does not get the source link unless it is a property of something. Since you just pass it a function, two-way binding is not performed. This has been noted before , recorded as a problem here and behavior is exposed in this problem .

This is not an ideal solution, but you can control the serialization of objects using toJSON methods. This will allow you to create what seems like an array of strings, but still observable in your application.

 var Item = function(name){ this.name = ko.observable(name); }; Item.prototype.toJSON = function(){ //special note: knockout already unwraps the observable for you return this.name; }; 

Here is the fiddle


Update

See slipheeds answer for a solution that just uses the binding that I prefer to this method. Leaving this answer if others prefer it

+3
source

As noted by the links posted by @Tyrsius, this is a knockout error (?).

The simplest workaround is to use $parent.items()[$index()] , as seen from this script: http://jsfiddle.net/r8fSg/ . Note that $parent.items() is the observable array of elements used in 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()); 
+13
source

In Knockout 3.0 and above, using $rawData instead of $data solves this problem. It is also referred to as a solution @ https://github.com/knockout/knockout/issues/708#issuecomment-27630842

+2
source

Another solution is to use the Repeat binding ( https://github.com/mbest/knockout-repeat ), which provides this functionality. Here your example is updated to use Repeat: http://jsfiddle.net/LDNeA/1/

 <div data-bind="repeat: array1"> <p><input data-bind='value: $item' /></p> </div> 
+1
source

All Articles