Carlo Moretto
Carlo Moretto

Reputation: 365

Knockout update model with ko.mapping

When we apply the ViewModel for the first time everything works fine, but if we reapply the mapping after the computed fields has been created, they are deleted. This code obviously works if we don't change the key

http://jsbin.com/ojabaf/14/edit

var modelJs = {test:{
  list: [{name: 'a', val: 5, list: [ {name:'b', val: 11}, {name: 'c', val: 13}  ]}]}
};

var mapping = { 
    'list': {
        key: function(data) { return ko.utils.unwrapObservable(data.name); }
    },
  'name': {
    key: function(data) { return ko.utils.unwrapObservable(data.name); }
  }
};

var model = ko.mapping.fromJS(modelJs, mapping);

ko.utils.arrayForEach(model.test.list(), function(item) {
  item.comp = ko.computed({read: function() { return this.val() * 2; }  , owner: item });
  ko.utils.arrayForEach(item.list(), function(item2) {
    item2.comp = ko.computed({read: function() { return this.val() * 3; }  , owner: item2 });  
  });
});

ko.applyBindings(model);

$('button').click(function () {
  var modelJs = {test: {val: 3, list: [{name: 'b', val: 7, list: [ {name:'s', val: 15}, {name: 'c', val: 17} , {name: 'd', val: 17}, {name: 'f', val: 17}]}]}};
  ko.mapping.fromJS(modelJs, model);
});

Is there a way to recalculate those computed fields with the ko.mapping, and without refreshing the page?

I also tryed with templates... http://jsbin.com/ojabaf/15/edit

Upvotes: 1

Views: 1715

Answers (1)

Jeff Mercado
Jeff Mercado

Reputation: 134841

Rather than looping over your arrays and adding the comp computed observables to each item, set up your mapping so they are added when an item is created.

var mapping = {
  'list': {
    key: function (data) {
      return ko.utils.unwrapObservable(data.name);
    },
    create: function (options) {
      var mapped = ko.mapping.fromJS(options.data, {
        'list': {
          key: function (data) {
            return ko.utils.unwrapObservable(data.name);
          },
          create: function (options) {
            var mapped = ko.mapping.fromJS(options.data);
            return ko.utils.extend(mapped, {
              comp: ko.computed(function () {
                return this.val() * 3;
              }, mapped)
            });
          }
        }
      });
      return ko.utils.extend(mapped, {
        comp: ko.computed(function () {
          return this.val() * 2;
        }, mapped)
      });
    }
  },
  'name': {
    key: function (data) {
      return ko.utils.unwrapObservable(data.name);
    }
  }
};
var model = ko.mapping.fromJS(modelJs, mapping);

http://jsbin.com/asomiq/1/edit

Upvotes: 2

Related Questions