2011-12-27 41 views
59

knockout.js绑定表达式中,我可以使用$data, $parent, and $root pseudovariables。当我使用在JavaScript中声明的ko.computed observable时,如何获得这些伪变量的等价物?

我有一个父视图模型与一个孩子的集合,父视图模型有一个selectedChild观察。鉴于这种情况,我可以使用数据绑定表达式添加到任何一个孩子正在选择一个CSS类:“我会选择”

<ul data-bind="foreach: children"> 
    <li data-bind="text: name, 
        css: {selected: $data === $root.selectedChild()}, 
        click: $root.selectChild"></li> 
</ul> 
<script> 
vm = { 
    selectedChild: ko.observable(), 
    children: [{name: 'Bob'}, {name: 'Ned'}], 
    selectChild: function(child) { vm.selectedChild(child); } 
}; 
ko.applyBindings(vm); 
</script> 

但我的ViewModels会得到比较复杂,我想能够做的不仅仅是将单个CSS类添加到单个元素。我真的想在子viewmodel上创建一个isSelected计算属性,这样我就可以添加其他依赖于它的计算属性。

我已经尝试了编写JavaScript,指的$data$root,在关闭的机会,淘汰赛可能定义这些变量并以某种方式让他们在范围上时,它调用我computed计算器功能:

{ 
    name: 'Bob', 
    isSelected: ko.computed(function(){ return $data === $root.selectedChild(); }) 
} 

但没有这样的运气:在我的评估者function里面,$data$root都是undefined

我也尝试在我的评估程序中使用ko.contextFor,因为它确实可以访问$data$root。不幸的是,在我的评估器功能中,contextFor也总是返回undefined。 (无论如何,我并没有对这个策略寄予厚望 - 如果我必须像这样背对背,那么淘汰赛将会如何跟踪依赖关系还不清楚。)

我总是可以手动设置属性,每个子视图模型引用父视图模型。但我知道淘汰赛有能力为我做这件事,而且我想至少在我写自己的作品之前先探讨一下我是否可以使用它的机制。

现在看来似乎应该是可以翻译上面绑定表达式的计算观察到的 - 毕竟,that's what knockout already does

另一个绝招是声明绑定简单地计算观测实现。

但我如何去与$data$root pseudovariables打交道时,我在写我自己的计算观察到的?

回答

76

伪变量仅在数据绑定的情况下可用。视图模型本身理想上不应该知道或显示视图的任何依赖关系。

因此,当在视图模型中添加计算的observables时,您不知道它将如何被绑定(比如什么是$ root)。视图模型或视图模型的一部分甚至可以分别绑定到不同级别的页面的多个区域,因此根据您开始使用的元素,伪变量会有所不同。

这取决于你想要完成什么,但是如果你想要你的孩子有一个isSelected计算的观测值,它指示这个项目是否与父视图模型上选择的项目相同,那么你将需要找到一种让父母可以得到的方法。

一种选择是将父项传递给子项的构造函数。您甚至不需要将指针添加到父级作为子级的属性,并且可以直接在计算的observable中使用它。

喜欢的东西:

var Item = function(name, parent) { 
    this.name = ko.observable(name); 
    this.isSelected = ko.computed(function() { 
     return this === parent.selectedItem();   
    }, this); 
}; 

var ViewModel = function() { 
    this.selectedItem = ko.observable(); 
    this.items = ko.observableArray([ 
     new Item("one", this), 
     new Item("two", this), 
     new Item("three", this) 
     ]); 
}; 

样品在这里:http://jsfiddle.net/rniemeyer/BuH7N/

如果所有你关心的是所选择的状态,那么你就可以调整它传递给selectedItem可观察到孩子的构造就像一个参考:http://jsfiddle.net/rniemeyer/R5MtC/

如果你的父视图模型存储在一个全局变量中,那么你可以考虑不将它传递给子代并直接使用它:http://jsfiddle.net/rniemeyer/3drUL/。尽管如此,我更愿意将参考传递给孩子。

+0

谢谢你的第二个例子! – vittore 2011-12-27 21:57:38

+0

如何在root上调用函数以及在相同的绑定中单击$ root.selectedItem? – FutuToad 2013-03-13 16:52:55

+0

例如,这不起作用:点击:函数(){$ parent.openAlertDialogueEdit($ data)} // $数据似乎是一个副本,而不是实际的参考 – FutuToad 2013-03-13 16:54:13

-7

在foreach绑定中使用$context而不是$parent

1

根据我的经验,如果Item在应用程序期间生效,@RP Niemeyer的答案中的方法就没有问题。但是,如果不是,它可能导致内存泄漏,因为Item的可计算可观察性设置与ViewModel的反向依赖关系。再说一次,如果你永远不会摆脱任何Item对象。但是如果你试图摆脱Item s他们不会收集垃圾,因为淘汰赛仍然会有反向依赖参考。

可以确保处置()的计算,也许在Item清理()方法时,该项目消失被调用,但你要记得做,只要去除Item秒。

相反,为什么不使Item不那么聪明,并且ViewModel它被选中时会告诉它?只要Item的​​是一个普通的老观察者,然后在ViewModel订阅selectedItem并在该订阅内更新。

或者,使用@RP Niemeyer的pub/sub solution。 (公平地说,这个解决方案是在他回答完这个问题后出现的。)但是,你仍然需要清理,因为它也会产生逆向依赖。但至少有更少的耦合。

有关更多详细信息,请参阅my recent question对此同一主题的回答。

相关问题