如何在knockoutjs中更新observable数组元素

How to update observable array element in knockoutjs?

本文关键字:更新 observable 数组元素 knockoutjs      更新时间:2023-09-26

我有以下JavaScript数组,

[{"unitPrice": 2499,"currency":"$","productId":1,"retailerId":1,"productName":"XX ","formattedPrice":"$ 2,499","productImage":"Images/2012_08_12_00_45_39_4539.jpg","productQuantity":"9","totalPrice":19992},
{"unitPrice": 4999,"currency":"$","productId":2,"retailerId":1,"productName":"XX","formattedPrice":"$ 4,999","productImage":"Images/2012_08_12_00_46_45_4645.jpg","productQuantity":2,"totalPrice":9998},
{"unitPrice":4555,"currency":"$","productId":1,"retailerId":1,"productName":"XXXXX","formattedPrice":"$ 4,555","productImage":"Images/2013_02_12_10_57_49_5749_9868.png","productQuantity":3,"totalPrice":13665}] 

这是相关的html,

<table>
<tbody data-bind="foreach: $root">
                    <tr>
                        <td><img width="45" height="45" alt="" data-bind="attr:{src: productImage}"/></td>
                        <td><span data-bind="html: productName"></span></td>
                        <td><span data-bind="html: formattedPrice"></span></td>
                        <td><input type="number" class="quantity" data-bind="value: productQuantity, attr:{'data-id': productId }"  /></td>
                        <td><span data-bind="html: totalPrice"></span></td>
                    </tr>
                </tbody>
</table>

然后我创建了一个可观察阵列,作为

observableItems = ko.observableArray(items);
ko.applyBindings(observableItems);

现在我可以使用获得特殊元素

       var obj = ko.utils.arrayFirst(list(), function (item) {
            return item.productId === id;
        });

然而,当我改变时,

item.productQuantity = 20;

但是UI没有更新。也尝试过,

item.productQuantity(item.productQuantity)

但是获取错误productQuantity不是的函数

上述行为是因为只有数组是可观察的,而不是数组中的单个元素或每个元素的属性。

执行item.productQuantity = 20;时,这将更新属性,但由于它不是可观察的,因此不会更新UI。

类似地,item.productQuantity(20)会给你一个错误,因为productQuantity不是可观察的。

您应该考虑为数组中的每个元素定义对象结构,然后将该类型的元素添加到可观察数组中。一旦完成,您将能够执行类似item.productQuantity(20)的操作,并且UI将立即自我更新。

EDIT添加了OP提供的功能:)。此函数将把数组中元素的每个属性转换为可观测值。

function convertToObservable(list) 
{ 
    var newList = []; 
    $.each(list, function (i, obj) {
        var newObj = {}; 
        Object.keys(obj).forEach(function (key) { 
            newObj[key] = ko.observable(obj[key]); 
        }); 
        newList.push(newObj); 
    }); 
    return newList; 
}

结束编辑

如果您无法更改这段代码,您也可以执行类似observableItems.valueHasMutated()的操作。然而,这不是一件好事,因为它向KO和UI发出信号,表明整个数组已经更改,UI将根据绑定渲染整个数组。

您可以轻松使用ko.mapping插件将对象转换为可观察对象:http://knockoutjs.com/documentation/plugins-mapping.html

将常规JS实体转换为可观察实体:

var viewModel = ko.mapping.fromJS(data);

将可观察对象转换为常规JS对象:

var unmapped = ko.mapping.toJS(viewModel);