10

请看我的文字。我尝试使用敲除js和foreach的observableArray来计算数组的数据。示例 1 工作正常:如果您更改字段中的数据,则会计算总和。但是示例 2 不起作用。

<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>
4

2 回答 2

6

编辑:得到小提琴工作,Raffaele 说你需要将可观察对象包装在一个对象中是正确的,但你可以在数组创建本身中做到这一点,我喜欢使用 ko.utils 来解开我的可观察对象,它做同样的事情对于可观察的,但如果有一个不可观察的传递给它,它不会崩溃。有关完整示例,请参见小提琴

observableArray 不会使传递的值可观察,这是一个常见的错误。observableArray 只观察对数组的修改,而不是值。如果你想让你的数组中的值是可观察的,你必须这样做。

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());

现在应该使用上面的示例。

于 2012-10-01T19:54:04.717 回答
6

文档说:

关键点:observableArray跟踪数组中有哪些对象,而不是那些对象的状态

简单地将一个对象放入 observableArray 并不能使该对象的所有属性本身都可观察。当然,如果您愿意,您可以使这些属性可观察,但这是一个独立的选择。observableArray 只跟踪它持有的对象,并在添加删除对象时通知侦听器。

您的第二个示例不起作用,因为输入字段的值未绑定到数组中的值。数组中的值在foreach绑定中仅使用一次,但是当您在输入框中键入时,不会触发 KO。

这是一个实现了解决方案的工作小提琴。我用了一个助手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());

和以下标记

<div>
    <p>
    <!-- ko foreach: fields -->
    <input data-bind="value: $data.value" />
    <!-- /ko -->
    <span data-bind="text: sum"></span>
    </p>
</div>​
于 2012-10-01T19:55:51.050 回答