Javascript 获取ObservalArray项的子属性以触发更改 问题

Javascript 获取ObservalArray项的子属性以触发更改 问题,javascript,knockout.js,Javascript,Knockout.js,我有一个shoppingcartviewmodel,带有cartimes视图模型的observearray 当我更新我的cartitems视图模型的subtotal属性时,我的shoppingcartviewmodel上的计算可观察对象需要更新,但我不知道如何让它触发更新 例子 那么在我看来,我有类似的东西 <ul data-bind='foreach: cartItems'> <!--other stuff here --> <input type

我有一个
shoppingcart
viewmodel,带有
cartimes
视图模型的
observearray

当我更新我的
cartitems
视图模型的
subtotal
属性时,我的
shoppingcart
viewmodel上的计算可观察对象需要更新,但我不知道如何让它触发更新

例子 那么在我看来,我有类似的东西

<ul data-bind='foreach: cartItems'>
    <!--other stuff here -->
    <input type='text' data-bind="value: quantity, valueUpdate: 'afterkeydown'"/>
</ul>

<span data-bind='value: grandTotal'></span>
这是假设的工作,我只是在某个地方搞砸了线,还是我需要添加一些其他东西来更新

现在,当文本框中的数量更改时,范围中的总计将不会更新。我假设这是因为这个子属性实际上不算作正在更改的cartItems集合


在这里触发集合更新的好方法是什么?

您没有从您的
grandTotal
计算中返回任何内容。此外,您还试图将
subTotal
函数添加到正在运行的
total
中,而不是其返回值。您需要使用括号调用,以便调用在
cartItem
上计算的项目

function shoppingcart() {
    var self = this;
    self.cartItems = ko.observableArray([]);
    self.grandTotal = ko.computed(function() {
        var total = 0;
        _.each(self.cartItems(), function (item) {
            total += item.subTotal(); // need parenthesis to invoke
        }
        return total; // return a value, otherwise function is void
    }

    //inital load of the data
    dataservice.loadCartItems(self.cartItems);
}

function cartItem() {
    var self = this;
    self.quantity = ko.observable(0);
    self.price = 0.00;

    self.subTotal = ko.computed(function() {
        return self.price * self.quantity();
    }
}

如果我理解正确的话,主要的问题是当其中一个元素发生变化时,你需要触发一个observableArray突变。这是可以做到的,但我不知道这是否是一个最佳实践。请参阅以下内容以了解替代实现:

此fiddle的示例解决方案调用valueHasMutated手动:

html:


呃,是的,这些实际上都是打字错误,因为我只是在脑海中输入了示例,但这让我在实际代码中发现了错误(非常类似的问题)。谢谢看起来我刚刚摸索出了我的代码,如果子项是可观察的,那么它确实可以开箱即用。但是+1带来的价值发生了变化。我在这里不需要它,但很高兴知道。我明白你的意思了,不确定最佳实践..是否至少在本例的子项中保留对父数组的引用是不正确的
function shoppingcart() {
    var self = this;
    self.cartItems = ko.observableArray([]);
    self.grandTotal = ko.computed(function() {
        var total = 0;
        _.each(self.cartItems(), function (item) {
            total += item.subTotal(); // need parenthesis to invoke
        }
        return total; // return a value, otherwise function is void
    }

    //inital load of the data
    dataservice.loadCartItems(self.cartItems);
}

function cartItem() {
    var self = this;
    self.quantity = ko.observable(0);
    self.price = 0.00;

    self.subTotal = ko.computed(function() {
        return self.price * self.quantity();
    }
}
<ul data-bind='foreach: cartItems'>
    <!--other stuff here -->
    <input type='text' data-bind="value: quantity, valueUpdate: 'afterkeydown'"/>
     * <span data-bind="text:price"></span>
    = <span data-bind="text:subTotal"></span>
    <br />
</ul>

<span data-bind='text: grandTotal'></span>
function cartItem(q, p, a) {
    var self = this;
    self.quantity = ko.observable(q);
    self.price = p;
    self.parentArray = a;

    self.subTotal = ko.computed(function() {        
        var subtotal =  parseFloat(self.price,10) * parseFloat(self.quantity(),10);
        self.parentArray.valueHasMutated();
        return subtotal;
    },self);
}


function shoppingcart() {
    var self = this;
    self.cartItems = ko.observableArray();
    self.cartItems([
        new cartItem(10,100, self.cartItems),
        new cartItem(1,3, self.cartItems),
    ]);
    self.grandTotal = ko.computed(function() {
        var total = 0;
        ko.utils.arrayForEach(self.cartItems(), function (item) {
            total += item.subTotal();
        });
        return total;
    }, self);

    //inital load of the data
    //dataservice.loadCartItems(self.cartItems);
}

        ko.applyBindings(new shoppingcart())