我设置了父子视图模型对象结构,需要更新子项中父项的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中实现此操作,是否有任何其他模式建议?或者我或多或少地坚持这两个选项?
答案 0 :(得分: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);
};
};
在这种情况下,您的绑定看起来像:
<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
(看起来像:{ {3}})。我通常使用一个单独的方法来显式,给它一个正确的名称(动作),如果有额外的处理需要在设置项目之前或之后完成。
在KO 2.0之前(其中引入了$root
和$parent
以及将数据作为第一个arg传递给click
和event
处理程序的更改),I曾经使用过你建议的第一种方法。你可以做的一件事实际上不是创建子属性(this.parentSelectedItem
)而是直接在parentSelectedItem
方法中引用select
(作为参数传递),因为它将由于创建的闭包,在函数中可用。