How can I bind a ko.observableArray of strings?

2019-04-07 00:47发布

问题:

I'm trying to bind a ko.observableArray of strings to a template, but I'm unable to get the template to pick up changes in the strings inside the array.

If I bind a set of objects instead of a set of strings, I get updates to the JSON, but they don't trigger anything until I actually change the first, non-array value. I'd prefer to find an array of strings, however, as I will be able to post the data model directly back to the server without any post-processing.

How can I get the updates to my arrays of strings to trigger, and how can I ensure that they correctly trigger changes without having to update a non-array value?

If it's not possible to bind to an observable array of strings, how I can get the events to trigger when updating the objects inside of the observable array?

See the example here: http://jsfiddle.net/gcEHC/2/

In this example, array3's data will be reflected in the model when value is changed, but changes to array1 and array2's data will never show up.

JS:

var ViewModel = function() {
    this.value = ko.observable("hi")
    this.array1 = ko.observableArray(["hi", "there"]);
    this.array2 = ko.observableArray([ko.observable("hi"), ko.observable("there")]);
    this.array3 = ko.observableArray([{ data: "hi" }, { data: "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 data-bind="foreach: array3">
        <p><input data-bind='value: data' /></p> 
    </div>
</div>

<pre data-bind="text: ko.toJSON($data)"></pre>

回答1:

From the docs:

Simply putting an object into an observableArray doesn’t make all of that object’s properties themselves observable. Of course, you can make those properties observable if you wish, but that’s an independent choice. An observableArray just tracks which objects it holds, and notifies listeners when objects are added or removed.

You need to create an object that has an observable property (of your string). Then make an observableArray of those objects.

For example, here's an example that updates the property of an object 2 seconds after the bindings are applied:

var item = function(text) {
    var self = this;

    self.Name = ko.observable(text);
}

var vm = {
    items: ko.observableArray([
        new item('one'),
        new item('two'),
        new item('three')
        ])
}

ko.applyBindings(vm);
setTimeout(function() {
    vm.items()[1].Name('updated!');
}, 2000);

Here's a complete, runnable sample: http://jsfiddle.net/psteele/z6gbM/



回答2:

In KO 3, if you point to $rawData in the binding, the array2 example works as expected.