可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Please, look at my text. I try to use observableArray of knockoutjs and foreach to compute data of array. Example 1 works fine: total sum computed if you change data in the fields. But Example 2 is not working.
<html> <head> <title></title> <script type='text/javascript' src='/js/jquery-1.8.2.min.js'></script> <script type='text/javascript' src='/js/knockout-2.1.0.debug.js'></script> </head> <body> <p>Example 1</p> <div> <p> <input data-bind="value: fnum1" /> <input data-bind="value: fnum2" /> <span data-bind="text: ftotsum"></span> </p> </div> <p>Example 2</p> <div> <p> <!-- ko foreach: fields --> <input data-bind="value: $data" /> <!-- /ko --> <span data-bind="text: ltotsum"></span> </p> </div> </body> <script> function vm(){ //Calc Example 1 var self = this; self.fnum1 = ko.observable(1); self.fnum2 = ko.observable(2); self.ftotsum = ko.computed(function(){ return parseFloat(self.fnum1()) + parseFloat(self.fnum2()); }); //Calc Example 2 self.fields = ko.observableArray([1, 2]); self.ltotsum = ko.computed(function(){ var total = 0; ko.utils.arrayForEach(self.fields(), function(item) { total += parseFloat(item); }) return total; }); }; ko.applyBindings(new vm()); </script> </html>
回答1:
EDIT: Got fiddle working, Raffaele is correct in saying you need to wrap the observable inside an object, but you can do it within the array creation itself and I like to use the ko.utils to unwrap my observables, it does the same thing for observables but it won't crash if there is a non-observable passed to it. See fiddle for full example.
An observableArray doesn't make the values passed observable, this is a common mistake. An observableArray just observes the modifications to the array and not the values. If you want to have your values inside your array be observable you have to make them so.
function vm(){ //Calc Example 1 var self = this; self.fnum1 = ko.observable(1); self.fnum2 = ko.observable(2); self.ftotsum = ko.computed(function(){ return parseFloat(self.fnum1()) + parseFloat(self.fnum2()); }); //Calc Example 2 self.fields = ko.observableArray([{"num":ko.observable(1)},{"num":ko.observable(2)}]); self.ltotsum = ko.computed(function(){ var total = 0; ko.utils.arrayForEach(self.fields(), function(item) { total += parseFloat(ko.utils.unwrapObservable(item.num)); }); return total; }); }; ko.applyBindings(new vm());
Should work with the example above now.
回答2:
The documentation says:
Key point: An observableArray
tracks which objects are in the array, not the state of those objects
Simply putting an object into an observableArray doesn’t make all of that object’s properties themselves observable. Of course, you can make those properties observable if you wish, but that’s an independent choice. An observableArray just tracks which objects it holds, and notifies listeners when objects are added or removed.
Your second example doesn't work because the value of the input fields is not bound to the values in the array. That values in the array are used only once, in the foreach
binding, but when you type in the input boxes, nothing triggers KO.
Here is a working fiddle with a solution implemented. I used a helper ObsNumber
function vm(){ var self = this; var ObsNumber = function(i) { this.value = ko.observable(i); } self.fields = ko.observableArray([new ObsNumber(1) , new ObsNumber(2)]); self.sum = ko.computed(function(){ var total = 0; ko.utils.arrayForEach(self.fields(), function(item) { total += parseFloat(item.value()); }); return total; }); }; ko.applyBindings(new vm());
and the following markup