35

I'm trying to replace all of the contents of an item in an observableArray with new content.

var oldLocation = ko.utils.arrayFirst(self.locations(), function (item) {
    return item.id == value.id;
});
self.locations.replace(self.locations.indexOf(oldLocation), new location(value));
self.locations.valueHasMutated();

I've also tried

self.locations[self.locations.indexOf(location)] = new fizi.ko.models.location(value);

But nothing is working. The index is being properly retrieved but the update of the item isn't happening.

bflemi3
  • 6,698
  • 20
  • 88
  • 155
  • What do you mean on "But nothing is working."? You don't have the new item in the array? Or you don't see the replace in the UI? Please post your html and bindings and also how a location object looks like! – nemesv Mar 15 '13 at 19:47
  • both. The model isn't updated and neither is the ui since the model isn't updated. – bflemi3 Mar 15 '13 at 19:55

3 Answers3

53

The replace function accepts two parameters, the item you want to replace and the new item you want to replace it with. You are passing in the index in place of the item to replace so it doesn't work.

The replace call should be:

self.locations.replace(oldLocation, new location(value));

On a side note, you shouldn't need the valueHasMutated() call there, it will get invoked by the replace() call.


Side note, many of the native Array functions are available for observable arrays. They are forwarded to the underlying array value triggering notifications of mutations as needed. These include:

pop, push, reverse, shift, sort, splice, unshift, slice (readonly).

Knockout provides these additional methods which should be documented here (currently v3.5.1):

remove, removeAll, destroy, destroyAll, indexOf, replace, sorted, reversed

Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
  • 13
    I've got to ask, where on earth is the documentation that mentions the replace method on an observable array? I've looked and looked, and couldn't see it anywhere in the documentation! – Paul Manzotti Mar 15 '13 at 19:59
  • 5
    @PaulManzotti - Item 7 of http://www.knockmeout.net/2011/06/10-things-to-know-about-knockoutjs-on.html mentions the added methods. – DaveB Mar 15 '13 at 20:55
  • 2
    @Paul: If ever in doubt, you could always view the (debug) source as well. Just search for `observableArray` and follow the references. – Jeff Mercado Mar 15 '13 at 21:29
  • @JeffMercado Good point, I should just have a wander around the code at some point. :) – Paul Manzotti Mar 15 '13 at 23:47
  • 6
    There is nothing wrong with this example, but in case anyone else is like me and didn't read it close enough, oldLocation is the OBJECT being replaced not the location in the array of the object to be replaced. – chrismay Mar 29 '15 at 17:58
4

I simply want to mention an alternative way to do it:

self.locations.splice(
  self.locations.indexOf(location),   // Index of the 1st element to remove
  1,                                  // Number of elements to remote at this index
  new fizi.ko.models.location(value)  // A param for each element to add at the index
);

Knockout includes splice in its documentation, but doesn't include replace: Knockout Obervable Arrays Docs. However, if you look at the source code you'll see that both functions are implemented (at least in KO 3.0, I don't know if replace was missing in previous versions).

JotaBe
  • 38,030
  • 8
  • 98
  • 117
3

I'm not aware of a replace method in JavaScript for arrays, or in Knockout. Am I missing something?

If you want to use your second method, then you need to access locations as an observable:

self.locations()[self.locations.indexOf(location)] = new fizi.ko.models.location(value);
self.locations.valueHasMutated();

though you don't when using indexOf, as there is a Knockout version of that for observable arrays.

wonea
  • 4,783
  • 17
  • 86
  • 139
Paul Manzotti
  • 5,107
  • 21
  • 27
  • 1
    I haven't seen it documented anywhere, but it's in the source code: https://github.com/knockout/knockout/blob/master/src/subscribables/observableArray.js – David Sherret Sep 11 '13 at 14:26