The Knockout link does not update the model

advertisements

I only started to use Knockout but I was already experienced with MVVM as applied in WPF. The issue I am encountering is that the my Knockout view model wrapping the model object does not update that original model. Here is a small example:

HTML

<select name="size" id="sel-size" data-bind="options: sizes, value: size"></select>

JS

// default settings
var settings = {
    size: 5
};

// settings view model
var settingsVM = function () {
    return {
        sizes: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
        size: ko.observable(settings.size)
    }
}();

// subscribe to changes
settingsVM.size.subscribe(function() {
    alert("Model: " + settings.size + " / VM: " + settingsVM.size());
})

ko.applyBindings(settingsVM);

View in JSFiddle

When the drop-down selection is changed, only settingsVM.size() from the view model is updated but settings.size from the model remains the same.

It seems that initializing an observable with a reference does not keep that reference as a backing field for the property accessor. What am I missing about the MVVM way of Knockout?


When you change the value of the select, it is in effect over-writing the contents of your size observable. If you want to set up a backing-field type arrangement, you'll have to use a computed observable with read/write.

Also, if you do want to update the original 'settings' object, you'll need to deal with that rather than the settings.size property alone. Something like this will keep the original model in step with the select:

// settings view model
var settingsVM = function () {
  var self=this;
  self.settings = ko.observable({
    size: 5
  });
  self.sizes =   [{size:1},{size:2},{size:3},{size:4},{size:5}];
  self.size = ko.computed({
          read:function(){
            return self.settings();
          },
          write:function(val){
            self.settings(val);
   }});
   self.size.subscribe(function() {

            alert("Model: " + self.settings().size + " / VM: " + self.size().size);
        });
};

ko.applyBindings(new settingsVM());

JSFiddle