更新父级时刷新选定的observable

时间:2013-11-21 14:58:27

标签: knockout.js

之前我问过这个问题,但没有得到太多回应。很明显,我不太清楚我想要实现的目标,所以我会再试一次。

Here's the jsFiddle to play around with


我正在开发一个应用程序,它将(以一定间隔)调用一个Web方法,该方法将读取数据库并构建一个返回的JSON字符串,用于构建我的视图模型。当我的视图模型发生变化时,我需要使用新数据改变所有选定的observable。

以此为基础模型示例。

var model = {
    people: [
        { forename: "Test", surname: "Person", numbers: [1,2,3] },
        { forename: "Another", surname: "Test", numbers: [4,5,6] }
    ]
};

很简单,一个人的表格会弹出一个模态时会弹出一个列表,显示所选人员的numbers列表。虽然这个模态是开放的,但数据可能会在幕后更新,所以如果选择了[测试人员](弹出模态),某人在某处将[7,8,9]添加到他们的numbers,那么我需要要刷新的模态显示这些添加。

这是一个基本的视图模型(为简洁起见使用ko.mapping):

var viewModel = {
    people: ko.mapping.fromJS(model.people),
    selectedPerson: ko.observable(null),
    refresh: function () {
        ko.utils.arrayForEach(model.people, function (person) {
            var last = person.numbers[person.numbers.length - 1];
            var newNumber = last + 1;
            person.numbers.push(newNumber);
        });
        ko.mapping.fromJS(model.people, this.people);
        console.log(ko.toJSON(this));
    }
};

当点击一行时,该人存储在selectedPerson中,这使我的模态在UI中可见(我正在使用Zurb Foundation):

<div id="modal" class="reveal-modal" data-bind="if: selectedPerson">

此模式显示一个numbers表,其中包含一个名为Update Observable的按钮 - 这会调用一个函数来模拟对基础模型的更改(在这种情况下,我将采用numbers中的最后一项将其递增1并将其推上)。完成后我再重新创建我的视图模型(为了简洁起见使用ko.mapping)并期望更新UI上的所有内容以反映更改 - 除了模态之外都很好。

在重新映射后查看我的视图模型的JSON,我可以看到视图模型已正确更新,但selectedPerson没有。我认为selectedPerson是一个参考,而不是副本,但我显然错了,我们最终得到了这个。

{
    "people": [
        {
            "forename": "Test",
            "surname": "Person",
            "numbers": [1,2,3,4,5,6,7,8]
        },
        {
            "forename": "Another",
            "surname": "Test",
            "numbers": [4,5,6,7,8,9,10,11]
        }
    ],
    "selectedPerson": {
        "forename": "Test",
        "surname": "Person",
        "numbers": [1,2,3]
    }
}

所以我想我的问题是:当基础模型发生变化时,如何更新selectedPerson(或实际上可能存在的任何其他选定的可观察量)?

1 个答案:

答案 0 :(得分:1)

您的问题是ko.mapping.fromJS(model.people, this.people)清空并重新创建您的people集合。但是您的selectedPerson仍然引用了旧person对象之一。

您需要告诉映射插件如何识别您的项目,以便更新它们:

ko.mapping.fromJS(model.people, 
                 { key: function(item) { return item.forename; } }, 
                 this.people); 

演示JSFiddle

或者作为替代解决方案,您可以在映射后将selectedPerson重置为新创建的person对象之一:

this.selectedPerson(ko.utils.arrayFirst(this.people(), function(item){
        return item.forename() == this.selectedPerson().forename();
    }, this));

演示JSFiddle