用于修改从子视图模型在父视图上可观察到的删除的模式

Pattern for modifying knockout observable on parent from child view model

本文关键字:视图 观察 模式 删除 修改 模型 用于      更新时间:2023-09-26

我已经设置了父子视图模型对象结构,需要从子对象更新父对象上的可观察对象。我基本上已经想出了两种模式:

1] 将父属性的引用传递给子属性,并从子属性中更新属性:

var ParentViewModel = function(){
    var self = this;
    this.selectedItem = ko.observable();
    this.child = ko.observable(new ChildViewModel(self.selectedItem));
}
var ChildViewModel = function(parentSelectedItem){
    var self = this;
    this.id = ko.observable();
    this.parentSelectedItem = parentSelectedItem;
    this.select = function(){
        self.parentSelectedItem(self);
    }
}

2] 在父对象上创建子对象的选择方法,并引用本地可观察到的父对象:

var ParentViewModel = function(){
    var self = this;
    this.selectedItem = ko.observable();
    var child = new ChildViewModel();
    child.select = function(){
        self.selectedItem(child);
    }
    this.child = ko.observable(child);
}
var ChildViewModel = function(){
    this.id = ko.observable();
}

这两种图案都没有让我大吃一惊。第一个将整个属性引用推送到子视图模型中,第二个在子视图模型的范围之外定义子函数。

关于如何在javascript中以干净和可测试的方式实现此操作,有人有其他模式建议吗?还是我或多或少地被这两个选项卡住了?

Knockout中最常见的模式是在您的父级上放置一个"selectChild"方法来接收子级。在大多数情况下,实际的子对象不需要知道它正在被选中。

然后在绑定中,可以绑定到$root.selectChild$parent.selectChild。传递给绑定到click/event绑定的处理程序的第一个参数是实际数据(在KO 2.0中),因此您的方法可以在父对象上运行,并将子对象作为第一个参数接收。

var Item = function(id, name) {
    this.id = id;
    this.name = ko.observable(name);    
};
var ViewModel = function() {
    var self = this;
    this.items = ko.observableArray([
        new Item(1, "one"),
        new Item(2, "two"),
        new Item(3, "three")
    ]);  
    this.selectedItem = ko.observable();
    this.selectItem = function(item) {
        self.selectedItem(item);
    };     
};

在这种情况下,您的绑定看起来像:

<ul data-bind="foreach: items">
    <li>
        <a href="#" data-bind="text: name, click: $root.selectItem"></a>
    </li>
</ul>

在jsFiddle中:http://jsfiddle.net/rniemeyer/anRsA/

你甚至可以进一步简化它。Observable是函数,您传递给它们的第一个参数用于设置它们的值,因此您甚至可以选择不包括selectItem方法,而直接绑定$root.selectedItem(看起来像:http://jsfiddle.net/rniemeyer/anRsA/1/)。我通常使用一个单独的方法来显式,给它一个合适的名称(操作),以防在设置项目之前或之后需要进行额外的处理。

在KO 2.0之前(其中引入了$root$parent,并将数据作为第一个arg传递给clickevent处理程序),我曾经使用您建议的第一种方法。实际上,您可以在那里做的一件事是不创建子属性(this.parentSelectedItem),而是直接在select方法中引用parentSelectedItem(作为参数传递),因为它将在函数中可用,因为创建了闭包。