Reputation: 86084
I've been looking at the documentation for knockout's observableArray
, and I'm having trouble figuring out how to do one of the most fundamental things you can do with an array: assign a value by index.
Things I've tried: (given oa = ko.observableArray([1,2,3])
)
oa(1, 10);
oa[1] = 10;
oa()[1] = 10;
oa.splice(1, 1, 10);
The last one seems work, but I'm concerned that .splice()
might be inefficient since it has to be concerned with shifting all the subsequent values. I'd prefer to just do simple index-based assignment.
I've created a jsfiddle that shows an observableArray being weird.
<ol data-bind="foreach: list">
<li data-bind="text: $data"></li>
</ol>
<script>
var model = {
list: ko.observableArray([3, 5, 7])
};
ko.applyBindings(model);
setTimeout(function() {
model.list()[1] = 55;
model.list.push(99);
model.list()[2] = 77;
}, 2000);
</script>
Upvotes: 3
Views: 5420
Reputation: 3706
Apply valueHasMutated property on your observable after modification
setTimeout(function() {
model.list()[1] = 55;
model.list.push(99);
model.list()[2] = 77;
model.list.valueHasMutated();
}, 2000);
Upvotes: 6
Reputation: 10260
Observable array notifies its listeners of changes (and thus causes corresponding views update) when mutating method is called or it is initialized with a new array.
oa()[i] = x;
oa(oa());
You can factor this out into an extension method:
ko.observableArray.fn.setItem = function(index, newValue) {
var items = this();
items[index] = newValue;
this(items);
};
foreach
binding is smart enough to detect that only one element is changed and there is no need to render other nodes again.
Upvotes: 3
Reputation: 3164
The way you assigned values in your fiddle works fine. If you do a console.log()
of your model.list() object, you can actually see that the values of the array are updated correctly.
The key thing to remember is the following bit in the documentation:
Key point: An observableArray tracks which objects are in the array, not the state of those objects
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.
This is the reason your view isn't being updated with the new value in index 2, because it's not an observable value. Something (quick and dirty) like this will work:
var model = {
list: ko.observableArray([ko.observable(3), ko.observable(5), ko.observable(7)])
};
model.list()[2](77); // Yeah, looks weird.
Upvotes: 1