KnockoutJS计算了observable undefined

时间:2014-05-14 20:21:37

标签: javascript knockout.js

我有这个非常简单的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);
});

4 个答案:

答案 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>
相关问题