我正在开发一个通过 AJAX 自动更新股票价格的股票观察网站。有了这个,我决定使用 knockout.js 来在变量更新时自动更新站点的 UI。
我的初始列表(在加载网页时)有以下示例 JSON 对象,它是从我的数据库中提取的,以确保所有公司都被拉出。对于这个例子,我有 4 家公司:
var companiesData =
[
{
"Date":"2013-04-19",
"company":"AAA",
"close":1.68,
"open":1.8
},
{
"Date":"2013-04-19",
"company":"BBB",
"close":13.68,
"open":12.8
},
{
"Date":"2013-04-19",
"company":"CCC",
"close":21.68,
"open":21.6
},
{
"Date":"2013-04-19",
"company":"DDD",
"close":19.68,
"open":17.8
}
]
我创建了一个 observableArray 对象并将其分配给 viewModel,如下所示:
var viewModel = {
companies = ko.observableArray(companiesData)
}
ko.applyBindings(viewModel);
然后我有一个 Ajax 函数,它提取更新的代码数据,其中仅包含那些已更新的公司和已更新的数据。请注意,我正在使用第三方 API 来提取更新的数据,因此我无法控制格式。假设只有 AAA 和 BBB 公司得到了更新:
var updatedCompaniesData =
[
{
"company":"AAA",
"close":1.90
},
{
"company":"BBB",
"close":15.08
}
]
当我用 updatedCompanies 更新 observableArray 时,整个 observableArray 被 updatedCompanies 替换,只返回 2 而不是 4,并且缺少属性。我在文档中读到
observableArray 跟踪数组中的对象,而不是这些对象的状态
因此我了解到,由于我只需要更新具有新数据的特定公司,但需要保留尚未更新的旧公司,因此我需要将每个公司的每个属性都设为 observable。所以我为此使用了映射插件,并为我的数组分配了一个键属性。这样,KO 将只查找密钥并更新其他属性(打开、关闭、日期),而不是删除公司并重新添加更新的公司。我还使用它的 create 方法在每个数组中添加了 ko.computed 函数。
ko.mapping.fromJS(companiesData, {
key: function(comp) {
return ko.utils.unwrapObservable(comp.company);
},
create: function(comp) {
return new Company(comp.data);
}
}, viewModel.companies);
我的问题是,如何更新每家公司的属性(只是价格、开盘价、收盘价),而不是 observableArray?更新 observableArray 本身会“重新加载”公司的数量。这样做的“淘汰”方式是什么?
我找到了更新选项,但我不确定如何在这种情况下使用它,因为我的 JSON 对象中没有数组名称。
var mapping = {
'name': {
update: function(options) {
return options.data + 'foo!';
}
}
}
另一个问题是,如果我不打算修改公司的数量,而只是打算更新每个公司在该数组中的属性,我是否必须使用 observableArray?