2

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

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

错误发生在第 50 行:

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

self.selectedOfferTypeDetailsType().Id 未定义

问题是,您会看到我在其他地方引用了相同的值,并且它似乎在其他地方工作正常。显然我错过了一些东西......我的头撞在墙上两天了,请用一双新的眼睛。

4

3 回答 3

2

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

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

不寻常的行为

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

让我们追踪

offerDetails 正在观察 SelectedOfferType,因此一旦您的第一个选择被绑定并将新值写入 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”。

这会触发写入,从而触发所有订阅者,从而导致您的错误。

惊人的!那么我该如何解决呢?

由于您编写的大部分代码都期望在 selectedOfferType 中有一个对象,因此我只需从您的选择中删除“optionsValue:'Id'”。

冗长的答案怎么样?:-D

于 2013-06-23T20:32:46.740 回答
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
});

我希望这有帮助。

于 2013-06-23T17:08:57.160 回答
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属性。

于 2013-06-23T17:36:44.063 回答