Javascript 敲除绑定不更新模型

Javascript 敲除绑定不更新模型,javascript,mvvm,knockout.js,Javascript,Mvvm,Knockout.js,我只是开始使用Knockout,但我已经有了在WPF中应用MVVM的经验。我遇到的问题是,包装模型对象的my Knockout视图模型不会更新原始模型。下面是一个小例子: HTML 更改下拉选择时,仅更新视图模型中的settingsVM.size(),但模型中的settings.size保持不变 似乎使用引用初始化可观察的,并不会将该引用保留为属性访问器的支持字段。关于MVVM的淘汰方式,我遗漏了什么?当您更改select的值时,实际上是过度写入您可观察的大小的内容。如果你想建立一个后备字段类

我只是开始使用Knockout,但我已经有了在WPF中应用MVVM的经验。我遇到的问题是,包装模型对象的my Knockout视图模型不会更新原始模型。下面是一个小例子:

HTML

更改下拉选择时,仅更新视图模型中的
settingsVM.size()
,但模型中的
settings.size
保持不变


似乎使用引用初始化
可观察的
,并不会将该引用保留为属性访问器的支持字段。关于MVVM的淘汰方式,我遗漏了什么?

当您更改select的值时,实际上是过度写入您可观察的大小的内容。如果你想建立一个后备字段类型的排列,你必须使用一个读/写的计算可观测值

此外,如果确实要更新原始的“settings”对象,则需要单独处理该对象,而不是settings.size属性。类似这样的操作将使原始模型与选择保持一致:

// 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());

淘汰赛的肮脏小秘密在于它不是真正的MVVM。它没有独立于viewmodeling的数据建模结构,所以它只是VVM。在普通的应用程序设计中,数据模型在服务器上,而应用程序中的“模型”是一组简单的AJAX例程,用于将数据片段引入viewmodel。Knockout与AJAX无关,因此如何处理应用程序的这一部分取决于您(但它通常非常简单)

在您的问题中,您希望模型自动更新以反映相应的viewmodel元素。那是多余的;不清楚您是否需要一些单独的东西来从viewmode复制一个值。viewmodel只能包含该模型。但是,如果您想做更多的model-y内容,因此确实需要将模型元素收集到一个结构中,Will Jenkins建议使用
subscribe
,这是响应viewmodel中更改的最直接的方法

在下面的评论中,Will Jenkins介绍了Knockout提供的用于在JSON和Observable之间转换的实用函数。这些功能对于在模型和viewmodel之间来回迁移也很有帮助


另请参见:

它不更新的原因是您的
设置。大小
不可观察,并且您的代码不提供将
设置。大小
用作html中的选定大小

// default Model for settings
function settings(){
    this.size = ko.observable(5);
}

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

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

ko.applyBindings(settingsVM);

参见更新的fiddle

,这确实意味着淘汰赛不具备“模型意识”。一旦您从服务器中取出一个模型,通过视图模型对其进行编辑,并希望将其保留回服务器,这意味着您必须从头重写您的模型?另外,必须订阅代理才能更新原始引用对我来说是多余的。你根本不需要使用订阅,这有点像是击倒imo的反模式。关于服务器往返,这很简单-您可以直接从json映射到您的vm,然后使用诸如ko.toJSON之类的实用函数来取消对vm的敲除并将其发回。请看这里:@Ucodia我想你会发现,如果你不坚持遵循一个单独模型的模式,那么淘汰就更简单了。您的模型在服务器上。你只需要把数据输入你的应用程序,然后把数据从你的应用程序写回服务器。这怎么会是一个“肮脏的小秘密”?MVVM的WPF风格也不是“模型感知”的,除非您专门将INPC添加到模型层,这对某些人来说是一个极具争议的话题。在WPF中,VM属性设置器通常将更改传播回模型;与之等价的是订户函数。他需要做的就是在
settingsVM.size.subscribe中更新模型,或者在提交时一次性完成。这和WPF并没有什么不同。@RoyJ我并不是坚持要遵循一种模式,这就是我要问淘汰赛在哪方面不同。现在,如果我将分解的模型包装到视图模型中,这也意味着我以后必须从视图模型重建模型,因为无法自动展开分解的模型(显然,您不会发回视图模型)。当您可以整齐地包装时,您不需要在没有任何额外步骤的情况下关心这样的事情,而且这当然不是视图模型的责任。
// 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());
// default Model for settings
function settings(){
    this.size = ko.observable(5);
}

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

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

ko.applyBindings(settingsVM);