【问题标题】:Adding and Updating observables in a part of the ViewModel with Knockout Mapping plugin - Not working使用 Knockout Mapping 插件在 ViewModel 的一部分中添加和更新 observables - 不工作
【发布时间】:2014-05-01 12:51:49
【问题描述】:

虽然这可能看起来像许多关于敲除映射插件和部分视图模型更新的类似问题,但我在所有搜索中都没有看到我在这里遇到的问题。

我将在下面通过一个示例进行详细说明,但简而言之,这就是我想要做的。

首先我使用 KO Mapping 插件的 ko.mapping.fromJS 从 Javascript 对象创建视图模型。 现在我只想用从服务器接收到的数据更新视图模型的一部分。所以。

  1. 我使用 ko.mapping.toJS 将 viewModel 转换为 JavaScript 对象
  2. 用服务器端的数据更新部分JS对象
  3. 使用更新的JS对象更新视图模型使用ko.mapping.fromJS

问题

  1. 第一次通过映射从 JS 对象创建的 observables 的值即使在更新后也保持不变
  2. 如果服务器数据对象中存在新属性,它们会显示它们的值 在更新的视图模型中附带 - 但不会在后续更新中更新为新值。

这是一个简化的例子。

观点

<div>
  <label data-bind="text: mainTitle"></label>
  <div data-bind="with: layer0">
    <label>Name - </label>
    <label data-bind="text: name"></label>
    <label>Type - </label>
    <label data-bind="text: type"></label>
  </div>
</div>

用于制作 ViewModel 的数据模型

  var dataModel =  {
     mainTitle: "Main Title",
     layer0:{
              itemDetails:{
                            name:"item1name",
                            type:"type1"
                          },
              otherDetails:{
                             prop1: "prop1Value",
                             prop2: "prop2Value"
                           }
    }

这个JS对象dataModel通过

转换成KO View Model
var viewModel = ko.mapping.fromJS(dataModel);

并通过 applyBindings 应用到上面的视图中,并按预期显示数据

现在我从服务器接收到这个 JS 对象

var newJSobjectFromServer =  {
         name: "item2Name",
         description: "item2Description"   // new property that was not on first model
         type: "type2"
        }

现在我做不到

viewModel.layer0.itemDetails(newJSobjectFromServer);

因为在由映射插件创建的viewModel 中,itemDetails 是属性而不是方法,只有 nametype 是方法

所以我先通过

从viewModel中提取一个JS对象
var viewModelJS = ko.mapping.toJS(viewModel);

然后我用新的服务器数据更新viewModelJS 的一部分

viewModelJS.layer0.itemDetails = newJSobjectFromServer;

所以viewModelJS变成了

{
 mainTitle: "Main Title",
 layer0:{
          itemDetails:{
                       name: "item2Name",
                       description: "item2Description"   // new property 
                       type: "type2"
                      }, 
          otherDetails:{ 
                         prop1: "prop1Value",
                         prop2: "prop2Value"
                       }
        }
}

然后我尝试通过

更新viewModel
ko.mapping.fromJS(viewModelJS , viewModel);

也试过了

ko.mapping.fromJS(viewModelJS , {}, viewModel);

但结果是

layer0.itemDetails.name() 仍然是 "item1"layer0.itemDetails.type() 仍然是 "type1" 而新的 observable layer0.itemDetails.description() 存在并且具有值“item2Description”

现在如果我用另一个服务器返回的对象重复更新

{
   name: "item3Name",
   description: "item3Desctiption" 
   type: "type3"
}

这次viewModel 中的所有值都与上次相同 layer0.itemDetails.name() 仍然是 "item1"layer0.itemDetails.type() 仍然是 "type1"layer0.itemDetails.description() 仍然是 "item2Description",因此视图中没有任何变化。

处理对象的复杂性使我有必要使用映射插件,只是示例被简化,但确实完全描述了我面临的问题。我真的在找人来指导我如何在上述确切场景中使用来自服务器的数据更新 viewModel 的那一部分。如果解决了这个问题,我可以将它应用到我所面临的更复杂的现实世界场景中。提前致谢。

【问题讨论】:

    标签: knockout.js knockout-mapping-plugin


    【解决方案1】:

    您的 UI 仍然绑定到同一个 ViewModel,并且再次运行映射不会刷新它。

    您可以使用不同的方法创建父视图模型并将“viewModel”设置为父视图模型的可观察成员。查看此小提琴,了解此行为的一个非常匆忙(但有效)的示例

    http://jsfiddle.net/barryman9000/4SKNd/2/

    var parentViewModel = function (data) {
        var _self = this;
        _self.Data = ko.observable('');
        _self.LoadData = function () {
            _self.Data(new viewModel(data));
        };
        _self.GetNewData = function (data, item) {
            _self.Data(new viewModel(newJSobjectFromServer));
        };
        _self.LoadData();
    };
    var viewModel = function (data) {
        var _self = this;
        ko.mapping.fromJS(data, {}, _self);
        _self.Data = ko.observable(data);
    };
    ko.applyBindings(new parentViewModel(dataModel));
    

    此外,如果 GetNewData() 函数进行 ajax 调用以获取数据,这仍会刷新您的 UI - 这就是我使用此“模式”的方式。

    更新

    一些想法:1) 重组您的数据,使其在所有情况下都是统一的。否则,您将以非常不同的方式构建每个视图模型,这只会在以后引起可读性问题。 http://jsfiddle.net/barryman9000/Q5RRr/1/

    2) 如果您无法重构数据,请放弃映射插件并手动执行所有操作。我会说这会产生更清晰的标记并让您更好地控制数据。 http://jsfiddle.net/barryman9000/5DD27/

    【讨论】:

    • 非常感谢您的建议 好吧,在现实世界的案例中,我认为我无法克服一些障碍。我叉了你的小提琴。 link 1) 第一个视图模型本身需要从 JS 对象来解释 - 尽管注入子视图模型可能是可能的 2) 请注意从服务器返回的对象不是整个结构 3) 最重要的是如引用 $root 或 $parent 的小提琴其他元素存在于由上下文绑定到 itemDetails 的元素中,因此子视图模型仍然可以工作。
    • 查看我的更新。你可能想放弃这个的映射插件
    猜你喜欢
    • 2013-02-23
    • 1970-01-01
    • 1970-01-01
    • 2012-12-18
    • 1970-01-01
    • 2013-09-07
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    相关资源
    最近更新 更多