jaffa
jaffa

Reputation: 27350

Cannot update Knockout UI with fresh data object

I'm currently having problems having the UI refresh when I'm getting new data from the server for a single item which is in an observableArray of wrapper objects which holds an object of several observables.

Consider the following:

var vm = {
....
localEdited: ko.mapping.fromJS(new ItemWrapper(defaultModelSerialised)), 
selected: ko.observable(null),
editItem: function(data) {
  // clone a temporary copy of data for the dialog when opening (*.localEdited on dialog)
  var clonedData = ko.toJS(data);
  ko.mapping.fromJS(clonedData, null, this.localEdited);

  // selected should now point to the item in the obserable array which will be refreshed
  this.selected(data);

  // open dialog...
},
submitDialog: function(data) {

   // submit data to server...

   // (1) commit the data back to UI (new item is return in resp.entity from server)
   vm.selected(new ItemWrapper(resp.entity));

   // at this point the UI isn't showing the updated value

   // (2) however if I do this it reflects the data change in the UI
   this.selected().Name("changed");  // updates the UI.
}

Can someone explain why passing in the ItemWrapper into vm.selected isn't updating the UI whereas in (2) it works. I don't want to have to set-up each property like in (2) for every property.

ItemWrapper looks like so:

function PoolWrapper(pool) {
    this.Name = ko.observable(pool.Name);

    // more properties...
} 

Upvotes: 6

Views: 1063

Answers (2)

Ibraheem
Ibraheem

Reputation: 2358

Something I also stumbled upon today that I thought I'd share:

If you clone using:

var clone = ko.mapping.fromJS(ko.mapping.toJS(itemToClone));

Then the clone will be stripped of any computed observables. They will exist as the last value of the function, but no longer function as a computed observable.

If your item is a complex model with computed observables that you would like to keep on your clone you can do the following:

var clone = ko.mapping.fromJS(ko.mapping.toJS(itemToClone), null, new itemModel());

Where itemModel is your complex model for your item containing your computed observables.

Upvotes: 0

RP Niemeyer
RP Niemeyer

Reputation: 114792

OK- the issue is that your clones end up with mapping meta-data on them and eventually this causes recursion when trying calling ko.mapping.fromJS.

The solution is to create your clones using ko.mapping.toJS instead of ko.toJS, so that you get a clean clone (without mapping meta-data).

Here is an updated fiddle: http://jsfiddle.net/rniemeyer/tDDBp/

Upvotes: 6

Related Questions