0

我正在开发一个通过 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 对象中没有数组名称。

来自 Knockout 映射插件文档

var mapping = {
'name': {
    update: function(options) {
        return options.data + 'foo!';
        }
    }
}

另一个问题是,如果我不打算修改公司的数量,而只是打算更新每个公司在该数组中的属性,我是否必须使用 observableArray?

4

1 回答 1

1

对,放弃最后一个答案。浏览了映射插件本身的代码后,它只是不是为了更新可观察数组中的单个项目而设计的,据我所知,它将删除不在更新数据中的任何数组项目。

因此,鉴于此,您不想使用映射插件来更新数据,只需对每个循环使用一个简单的:

ko.utils.arrayForEach(updatedCompaniesData, function (updatedCompany) {
    var company = ko.utils.arrayFirst(viewModel.companies(), function (item) {
        return item.Name() === updatedCompany.company;
    });

    if (company) {
        company.ClosingPrice(updatedCompany.close);
    }
});

工作jsFiddle

于 2013-04-23T14:21:57.127 回答