当可观察数组项的属性发生更改时,计算的可观察量不会发生变化

时间:2016-01-13 10:44:28

标签: javascript knockout.js

我正在使用knockout.js迈出第一步。我创建了这段代码,但它并不能让我满意,因为我的self.totals()函数在每次更改price列中的某些内容时都不会求和(只有在我更改整个{{1}时才有效通过添加新的,或删除旧的)。我在哪里犯了错误? jsfiddle

<tr>

2 个答案:

答案 0 :(得分:2)

这是一个经典的误解:一个可观察的数组通知其项目的变化,而不是其项目的属性。

例如,当整个元素列表被新元素更改,或添加元素或删除元素时,可观察数组会通知更改。在您的情况下,如果您添加新书或删除它,或更改书籍列表,您的计算可观察量将会更新。

如果您需要计算的observable来对图书价格的变化作出反应,那么您需要使price属性可观察。即你的书籍应该是这样的:

var books = [
{
    name : "Javascript",
    author : "David Flanagan",
    genre : "learning",
    price : ko.observable(100)
},
{
    name : "PHP",
    author : "Luke Welling",
    genre : "learning",
    price : ko.observable(120)
},

如果价格不是可观察的,那么ko无法检测到价格已经发生变化,而且这种情况不会发生。

你可以为每本书做这样的事情:

book.price = ko.observable(book.price)

将常规属性转换为可观察属性(可以在循环中轻松完成)。请记住在addBook函数上创建属性为observable。

由于calculate是一个访问可观察数组的计算observable,您不需要在addBookremoveBook中显式调用它,因为这个计算的observable会自动订阅observables它访问,这是可观察的数组本身,以及每本书的价格。

您可以在updated fiddle中看到所有这些内容。

我没有更新小提琴,以显示它是如何工作的,但是如果你试图序列化或存储书籍,价格将不会变得很苛刻,因为它们不再是属性,而是功能。所以,你必须扭转这个过程,即每本书:

book.price = ko.unwrap(book.price)

book.price = book.price()

注意:您应该组织代码,以便在将属性转换为可观察对象时反之亦然。如果您不仅对price感兴趣,而且对所有属性感兴趣,您可以使用ko.mapping plugin将属性转换为可观察对象,反之亦然,ko.fromJSko.toJS

答案 1 :(得分:1)

正如JotaBe所提到的,您正在编辑的各个元素是不可观察的。 self.books是一个observableArray,它只注意行级更改。

当值变化时,将元素设置为可观察对象的替代方法是通知observableArray它已被更改。为此目的,Observable具有valueHasMutated属性。在您的情况下,您对书籍的更改感兴趣,因此您可以绑定到那里的更改事件。

<td><input class='required form-control number' data-bind='value: price, event: {change: $parent.books.valueHasMutated}, uniqueName: true' /></td>

这是一种有点hacky的方法,因为将更改推送到更高级别的结构会导致不必要的依赖性触发,但在某些情况下它可以是一种方便的解决方法。