KnockOutJS - 得到一个'未定义'的值,不知道为什么

时间:2013-06-23 16:56:56

标签: knockout.js

http://jsfiddle.net/toddhd/XWgK5/2/

看着小提琴手是看到这个的最好方法。如果您在具有开发者模式的浏览器(例如Chrome)或带有FireBug的FF中运行它并运行代码,您将在控制台中看到错误。它告诉我,我试图读取的值是未定义的。

错误发生在第50行:

 if (item.Id == self.selectedOfferTypeDetailsType().Id) {

self.selectedOfferTypeDetailsType()。Id未定义

问题是,你会看到我在其他地方引用了这个相同的值,而且似乎在其他地方工作正常。显然我错过了一些东西......我的头靠在墙上两天了,可以用一双新鲜的眼睛。

3 个答案:

答案 0 :(得分:2)

Damien和jaux都有敏锐的眼睛,但在这种情况下他们只是部分正确。确实,Knockout计算在声明后立即进行评估,因此Knockout可以确定您的计算需要订阅哪些其他可观察对象,但

计算后定义的初始评估正在运行而没有问题。但是,只要您调用ko.applyBindings,您的选择就会被连接起来并开始使用您的视图模型,那就是您的错误发生时。

异常行为

一旦你的第一个选择(带有id = offerTypes)被绑定,它会做一些不寻常的事情:它会立即写入selectedOfferType 。这不是绑定选择通常工作的方式。通常,select会在用户更改内容之前不写入它的值,但在这种情况下,select绑定会立即将值写入SelectedOfferType。忍受我,我会告诉你我是如何发现错误的。

让我们来追踪

offerDetails正在观察SelectedOfferType,因此只要绑定了第一个select并将新值写入SelectedOfferType,offerDetails就会运行以检查它的值是否也已更改。在offerDetails中,您为selectedOfferTypeDetailsType写了一个值,该值警告其订阅者 - 订阅者包括“offer”。 “Offer”执行,但您只需将self.selectedOfferTypeDetailsType()设置为null(在offerDetails中),并且您无法读取“null”的“id”属性。

所以,问题是“为什么选择在绑定时将值写入SelectedOfferType?”答案在于你的绑定。初始化视图模型时,您似乎尝试使用offerTypes中的第二个值预设第一个下拉列表:

self.selectedOfferType = ko.observable(self.offerTypes()[1]);

和你的绑定

<select id="offerTypes" data-bind="options: offerTypes, ... value: selectedOfferType"></select>

同意您将值附加到您的选择中。但是,你将self.selectedOfferType设置为self.offerTypes()[1]中的对象,但是我在上面省略的绑定部分表示你的选项的值不是对象,而是等等位于“Id”属性中。

<select data-bind="... optionsValue: 'Id', ..."></select>

将selectedOfferType与对象一起填充,但将optionsValue赋值给属性会导致Knockout理解selectedOfferType中的值无效(不可选),因此Knockout会立即使用第一个可能的选项值更新selectedOfferType。在这种情况下,为'0'。

触发一次写操作,触发所有订阅者,从而导致错误。

真棒!那我该怎么解决呢?

由于您编写的大多数代码都是为了期望selectOfferType中的对象,因此我只需从您的选择中删除“optionsValue:'Id'”。

对于冗长的回答,这是怎么回事? :-D

答案 1 :(得分:1)

在这种情况下,您需要做的是对计算属性进行评估。

创建viewModel实例时,self.selectedOfferTypeDetailsType将返回undefined。将deferEvaluation设置为true,计算出的商品的评估是延迟,直到您“消费”(确实需要)计算的商品。

self.offer = ko.computed({
    read: function () {
        var o = 'Not Found';
        ko.utils.arrayForEach(self.offerTypeDetailsTypes(), function (item) {
            if (item.Id == self.selectedOfferTypeDetailsType().Id) {
                alert('Yay');
            }
        });
        return o;
    },
    deferEvaluation : true
});

我希望这会有所帮助。

答案 2 :(得分:0)

问题在于:

self.offerDetails = ko.computed(function() {
    var activeCategories = ko.observableArray();
    ko.utils.arrayForEach(self.offerTypeDetailsTypes(), function (item) {
        if (item.Id == self.selectedOfferType().Id)
            activeCategories.push(item.DisplayName);
    });
    self.selectedOfferTypeDetailsType(activeCategories()[0]); // PROBLEM!
    return activeCategories();
});
此时

self.selectedOfferTypeDetailsType设置为字符串,毫无疑问,当您稍后尝试访问它时,它没有Id属性。