我正在使用knockout.js迈出第一步。我创建了这段代码,但它并不能让我满意,因为我的self.totals()
函数在每次更改price列中的某些内容时都不会求和(只有在我更改整个{{1}时才有效通过添加新的,或删除旧的)。我在哪里犯了错误?
jsfiddle
<tr>
答案 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,您不需要在addBook
和removeBook
中显式调用它,因为这个计算的observable会自动订阅observables它访问,这是可观察的数组本身,以及每本书的价格。
您可以在updated fiddle中看到所有这些内容。
我没有更新小提琴,以显示它是如何工作的,但是如果你试图序列化或存储书籍,价格将不会变得很苛刻,因为它们不再是属性,而是功能。所以,你必须扭转这个过程,即每本书:
book.price = ko.unwrap(book.price)
或
book.price = book.price()
注意:您应该组织代码,以便在将属性转换为可观察对象时反之亦然。如果您不仅对price
感兴趣,而且对所有属性感兴趣,您可以使用ko.mapping plugin将属性转换为可观察对象,反之亦然,ko.fromJS
和ko.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的方法,因为将更改推送到更高级别的结构会导致不必要的依赖性触发,但在某些情况下它可以是一种方便的解决方法。