从儿童视图模型修改父母可观察的淘汰模式

Kod*_*hor 14 javascript design-patterns design-principles knockout.js

我有一个父子视图模型对象结构设置,需要更新子项中父项的observable.我基本上提出了两种模式:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

2]在父项上创建子项的select方法,并在本地引用父项observable:

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();
}
Run Code Online (Sandbox Code Playgroud)

这些模式都没有让我头疼.第一个将整个属性引用推送到子视图模型中,第二个将子函数定义在子范围之外.

有没有人有任何其他模式的建议,如何在javascript中以干净和可测试的方式实现此操作?或者我或多或少地坚持这两个选项?

RP *_*yer 20

在Knockout中执行此操作的最常见模式是在父项上放置一个"selectChild"方法,该方法接收子项.在大多数情况下,实际的孩子不需要知道它正在被选中.

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

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);
    };     
};
Run Code Online (Sandbox Code Playgroud)

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

<ul data-bind="foreach: items">
    <li>
        <a href="#" data-bind="text: name, click: $root.selectItem"></a>
    </li>
</ul>
Run Code Online (Sandbox Code Playgroud)

这里是jsFiddle:http://jsfiddle.net/rniemeyer/anRsA/

您甚至可以进一步简化它.Observables是函数,你传递给它们的第一个参数用于设置它们的值,所以你甚至可以选择不包含该selectItem方法并直接绑定$root.selectedItem(看起来像:http://jsfiddle.net/rniemeyer/anRsA/1 /).我通常使用一个单独的方法来显式,给它一个正确的名称(动作),如果有额外的处理需要在设置项目之前或之后完成.

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