14

我设置了一个父子视图模型对象结构,需要从子节点更新父节点的 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);
    }
}

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();
}

这些模式都没有让我兴奋不已。第一个将整个属性引用推送到子视图模型中,第二个定义了子范围之外的子函数。

关于如何以干净和可测试的方式在 javascript 中实现此操作,是否有人有任何其他模式建议?还是我或多或少只停留在这两个选项上?

4

1 回答 1

20

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

然后在您的绑定中,您可以绑定到$root.selectChildor $parent.selectChild。传递给绑定到单击/事件绑定的处理程序的第一个参数是实际数据(在 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/

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

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

于 2012-04-04T06:00:54.693 回答