2013-05-02 48 views
5

我需要使用Javascript和Knockout.js編輯Web應用程序中的整數數組。該數組將被綁定到文本框,並且每當更改任何文本框的值時,數組都會更新。當它得到更新時,元素的總和就會被計算出來。跟蹤更改 - observableArray中的可觀察元素

這是我第一次嘗試:http://jsfiddle.net/ZLs2A/0/。它不工作(爲任何元素鍵入新值時,總和值不會更新)。那時我意識到observableArray只會在插入或刪除項目後觸發sum函數。

<h4>Numbers</h4> 
<button data-bind="click: add">Add</button> 
<ul data-bind="foreach: numbers"> 
    <li> 
     <input data-bind="value: $data"></input> 
    </li> 
</ul> 
<span data-bind="text: sum"></span> 

function MyViewModel() { 
    var self = this; 

    self.numbers = ko.observableArray([ 
     1, 
     2, 
     3 
    ]); 

    self.sum = ko.computed(function() { 
     var items = self.numbers(); 
     var total = 0; 
     for (var i = 0; i < items.length; i++) { 
      total += parseInt(items[i]); 
     } 
     return total; 
    }); 

    self.add = function() { 
     var lastIndex = self.numbers().length - 1; 
     var lastValue = self.numbers()[lastIndex]; 
     self.numbers.push(lastValue + 1); 
    } 
} 

ko.applyBindings(new MyViewModel()); 

我的下一個嘗試是讓Numbers數組中的每個元素都是可觀察的(http://jsfiddle.net/ZLs2A/1/)。它沒有再次工作。

self.numbers = ko.observableArray([ 
    ko.observable(1), 
    ko.observable(2), 
    ko.observable(3) 
]); 

我最後的嘗試是創建一個新的類(ArrayItem)來保存元素的值在一個observable屬性中。這一次它工作! (http://jsfiddle.net/ZLs2A/3/

<h4>Numbers</h4> 
<button data-bind="click: add">Add</button> 
<ul data-bind="foreach: numbers"> 
    <li> 
     <input data-bind="value: value"></input> 
    </li> 
</ul> 
<span data-bind="text: sum"></span> 

function MyViewModel() { 
    var self = this; 

    self.numbers = ko.observableArray([ 
     new ArrayItem(1), 
     new ArrayItem(2), 
     new ArrayItem(3) 
    ]); 

    self.sum = ko.computed(function() { 
     var items = self.numbers(); 
     var total = 0; 
     for (var i = 0; i < items.length; i++) { 
      total += parseInt(items[i].value()); 
     } 
     return total; 
    }); 

    self.add = function() { 
     var lastIndex = self.numbers().length - 1; 
     var lastItem = self.numbers()[lastIndex]; 
     var newValue = parseInt(lastItem.value()) + 1; 
     self.numbers.push(new ArrayItem(newValue)); 
    } 
} 

function ArrayItem(value){ 
    var self = this; 
    self.value = ko.observable(value); 
} 

ko.applyBindings(new MyViewModel()); 

但是,我不喜歡必須創建這個新類ArrayItem。 有沒有什麼辦法擺脫它,讓示例工作只是有一個observableArray的可觀察元素(如我的第二次嘗試)?

+2

KO筆者回答[這(?可能重複的)問題(http://stackoverflow.com/questions/9510539/knockout-js-how-to-correctly-bind-an -observablearray),基本上和你的最終版本有一個'ArrayItem'構造函數類似(他只是內聯這個函數)。答案是一年之久,所以有些事情可能在同一時間發生了變化......如果沒有,似乎你已經回答了你自己的問題。 – Jeroen 2013-05-02 18:44:34

+0

可能值得一提的是Breeze.js與Knockout.js的集成,增加了變化追蹤等功能。 http://www.breezejs.com/ – 2013-05-02 19:10:21

回答

2

Knockout將不會跟蹤該值,但作爲解決方法,您可以使用事件按鍵或自己更改和更新值。見琴:http://jsfiddle.net/tkirda/ZLs2A/4/

function MyViewModel() { 
    var self = this; 

    self.numbers = ko.observableArray([ 
     1, 
     2, 
     3 
    ]); 

    self.onChange = function(val, e){ 
     var el = e.srcElement; 
     var newVal = parseInt(el.value); 
     var index = parseInt(el.getAttribute('data-index')); 
     self.numbers()[index] = newVal; 
     self.updateSum(); 
    } 

    self.sum = ko.observable(0); 

    self.updateSum = function() { 
     var items = self.numbers(); 
     var total = 0; 
     for (var i = 0; i < items.length; i++) { 
      total += parseInt(items[i]); 
     } 
     self.sum(total); 
    }; 

    self.updateSum(); 

    self.add = function() { 
     var lastIndex = self.numbers().length - 1; 
     var lastValue = self.numbers()[lastIndex]; 
     self.numbers.push(lastValue + 1); 
    } 
} 

ko.applyBindings(new MyViewModel()); 
+0

雖然這似乎與IE11一起工作,但jsfiddle示例中的總和不會更新Firefox 45.0.1中文本字段中值的更改 – Stefan 2016-04-21 08:08:58