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