【问题标题】:How to Refresh Knockout ViewModel Using Mapping Plugin如何使用映射插件刷新 Knockout ViewModel
【发布时间】:2015-02-02 18:05:37
【问题描述】:

我有以下 Knockout ViewModel:

var EditorViewModel = function () {

    var self = this;

    self.addData = function (_data) {
        ko.mapping.fromJS(_data, {}, self);
    };
};

这样使用的:

var viewModel = new EditorViewModel();
viewModel.addData(model);
ko.applyBindings(viewModel);

关于信息,viewModel.addData() 的数据来自 AJAX 调用。

第一次调用ko.applyBindings 时,View/ViewModel 的填充没有问题。但是,如果我稍后通过 AJAX 从服务器中提取新数据,然后调用:

viewModel.addData(someNewAjaxData)

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

然后 Knockout 不会使用新数据更新视图。希望这是一个微不足道的问题...?!

【问题讨论】:

  • 你能提供一个带有一些示例代码的 jsFiddle 链接吗?

标签: javascript knockout.js


【解决方案1】:

KnockoutJS Mapping 能够为项目指定密钥。这让 KnockoutJS 知道何时需要创建和更新项目。

var ItemViewModel = function(d){
    var self = this;
    
    self.id = ko.observable(d.id);
    self.text = ko.observable(d.text);
    
    // We assign it when the object's created to demonstrate the difference between an
    // update and a create.
    self.lastUpdated = ko.observable(new Date().toUTCString());
}
var EditorViewModel = function(){
    var self = this;
    
    self.items = ko.observableArray();
    
    self.addData = function(d){
        ko.mapping.fromJS(d, {
            'items': {
                'create': function(o){
                    return new ItemViewModel(o.data);
                },
                'key': function(i){
                    return ko.utils.unwrapObservable(i.id);
                }
            }
        }, self);
        console.info(self);
    }
    self.addMoreData = function(){
        self.addData({
            'items': [
                {id:1,text:'Foo'},
                {id:3,text:'Bar'}
            ]
        });
    }
}

var viewModel = new EditorViewModel();
viewModel.addData({
    items:[
        {id:1,text:'Hello'},
        {id:2,text:'World'}
    ]
});
ko.applyBindings(viewModel);
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>

<div class="container">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            
            <div class="panel panel-default">
                <div class="panel-heading">
                    <h3 class="panel-title">Hello, world!</h3>
                </div>
                <ul class="list-group">
                    <!-- ko foreach:items -->
                    <li class="list-group-item">
                        <span class="text-muted" data-bind="text:id"></span>
                        <span data-bind="text:text"></span>
                        <span class="text-danger pull-right" data-bind="text:lastUpdated"></span>
                    </li>
                    <!-- /ko -->
                    <li class="list-group-item" data-bind="visible:!items().length">
                        <span class="text-muted">No items.</span>
                    </li>
                </ul>
                <div class="panel-footer">
                    <a href="#" data-bind="click:addMoreData">Update</a>
                </div>
            </div>
            
        </div>
    </div>
</div>

请注意,在附加的 sn-p 中,第一项的 lastUpdated 值是如何在创建时分配的,但在更新时保持不变。这是因为映射器看到 ID 已经存在于 items 中并简单地更新了属性。但是,对于 id 为 3 的项目,会创建一个新模型。

【讨论】:

  • 谢谢布拉德。视图模型只包含一个对象(而不是对象数组)——这会影响所采用的方法吗?
  • @Graham:不应该。我只是碰巧将其分解以显示更多可用选项(create 选项)。它还可以更轻松地演示 lastUpdated 字段(以及它在更新期间如何保持静态)。
  • 我在 ViewModel 中包含以下内容:var EditorViewModel = function () { var self = this; self.addData = function (_data) { var mapping = { key: function (i) { return ko.utils.unwrapObservable(i.id); } } ko.mapping.fromJS(_data, mapping, self); }; self.isUpdate = ko.computed(function () { return self.id() !== 0; }, self, { deferEvaluation: true }); }; 但问题仍然存在 - 视图未更新。 :(
  • @Graham:你能修改我提供的 jsfiddle 并保存修改(然后粘贴链接)吗?
【解决方案2】:

所有淘汰赛投标都订阅了第一个创建的模型。您在每个 ajax 响应上重新创建绑定模型。您的问题似乎与此stackoverflow article 中讨论的类似。相同的可观察对象应该绑定到标记。

试试这个(也许你应该支持一个空模型绑定):

// in the start of app
var observableModel = ko.observable();
ko.applyBindings(observableModel);

// on every ajax call
var viewModel = new EditorViewModel();
viewModel.addData(model);
observableModel(viewModel);

【讨论】:

  • 谢谢 - 使用 observableModel 时的绑定语法是什么?例如data-bind="value: propertyName"在使用新模型时应该变成什么?
  • 如果你显示你的标记,我可以试着告诉你要改变什么。目前,恕我直言,您的绑定可能保持不变。
猜你喜欢
  • 2012-12-18
  • 2012-07-31
  • 2015-01-17
  • 2013-09-27
  • 2014-12-15
  • 2014-03-04
  • 2012-02-08
  • 2012-11-05
  • 2018-12-11
相关资源
最近更新 更多