我有这个非常简单的knockoutjs脚本。我的视图模型包含一个名为' modules'这是一个字符串数组。如果我有这样的foreach列表,它会打印每个项目的模块列表:
<tbody data-bind="foreach: items">
<tr>
<td data-bind="text: modules"></td>
</tr>
</tbody>
但是如果我想通过添加计算的observable来打印模块的数量:
<tbody data-bind="foreach: items">
<tr>
<td data-bind="text: numModules"></td>
</tr>
</tbody>
我遇到了问题。 &#39;未定义&#39;它不是我在计算函数的第一行所说的函数。我的js代码看起来像这样:
function AppViewModel(data) {
var self = this;
ko.mapping.fromJS(data, {}, this);
this.numModules = ko.computed(function() {
return self.modules().length;
});
};
$.getJSON("/api/items", function(data) {
var viewModel = new AppViewModel(data);
ko.applyBindings(viewModel);
});
答案 0 :(得分:6)
在这种情况下,计算机可能在属性实际存在之前尝试计算。默认情况下,ko.computed中未设置的一个参数是deferEvaluation参数...一旦设置了此参数,计算机将不会尝试计算AppViewModel的初始化。
this.numModules = ko.computed({
read: function() {
return self.modules().length;
},
deferEvaluation: true
);
在一个更挑剔的说明中,如果你定义'self = this',那么在下一行中设置你的计算用'this'的上下文,为什么你定义'self'?
答案 1 :(得分:1)
问题是您在ViewModel的 root 上定义numModules
,而您尝试执行的计算在modules
上属性每个item
。
因此,self.modules
确实未定义且无法调用,因为self
指的是根对象,而modules
是每个项目的属性。
请改为尝试:
function AppViewModel(data)
{
var self = this;
ko.mapping.fromJS(data, {}, this);
// defining the computed function on each 'item'
for (var i in self.items())
{
self.items()[i].numModules = ko.computed(function()
{
return this.modules().length;
}, self.items()[i]);
}
};
或者这样:
// defined on $root
self.numModules = function(item) {
return item.modules().length;
}
// but passing 'item' upon invocation
<td data-bind="text: $root.numModules($data)"></td>
答案 2 :(得分:0)
我不确定,但如果你这样做会怎么样:
function AppViewModel(data) {
var self = this;
this.modules = ko.obeservableArray();
ko.mapping.fromJS(data, {}, this.modules());
this.numModules = ko.computed(function() {
return self.modules().length;
});
};
答案 3 :(得分:0)
我发现解决问题最简单的方法,根本不添加任何特殊的js代码就是在html中这样做:
<td data-bind="text: modules().length"></td>