[英]knockout.js - nested array data and cascading pre-populated dropdown lists binding
我对knockout.js很新,但是,我一直很乐意在我的ASP.NET MVC 4项目中使用它,直到我遇到这个困扰我一段时间的障碍,似乎无法把我放在手指放在上面。
我正在处理的场景需要几个位置数据组合(区域,国家,城市),即级联下拉列表,这在输入新数据时不是问题,但我在尝试时遇到了问题编辑保存的数据。
数据采用JSON格式,具有嵌套数组,如下所示(为简化说明而缩写):
var newData =
[
{
"ID":1,
"Name":"Australia and New Zealand",
"Countries":[
{
"ID":13,
"Name":"Australia",
"Cities":[
{
"ID":19,
"Name":"Brisbane"
},
{
"ID":28,
"Name":"Cairns"
},
...
我怀疑我无法正确加载数据(或者更清楚地绑定它),因为我无法访问Region子阵列(包含Region的国家/地区)和Countries子阵列(包含国家/地区的城市) 。
然后是预先填充选项的问题,部分工作,viewmodel加载行数,但不选择任何东西。
这是VM:
var existingRows = [
{
"Region": 1,
"Country": 13,
"City": 19
},
{
"Region": 1,
"Country": 158,
"City": 3
}];
var Location = function (region, country, city) {
var self = this;
self.region = ko.observable(region);
self.country = ko.observable(country);
self.city = ko.observable(city);
// Whenever the region changes, reset the country selection
self.region.subscribe(function () {
self.country(undefined);
});
// Whenever the country changes, reset the city selection
self.country.subscribe(function () {
self.city(undefined);
});
};
var LocationViewModel = function (data) {
var self = this;
self.lines = ko.observableArray(ko.utils.arrayMap(data, function (row)
{
var rowRegion = ko.utils.arrayFirst(newData, function (region)
{
return region.ID == row.Region;
});
var rowCountry = ko.utils.arrayFirst(rowRegion.Countries, function (country) {
return country.ID == row.Country;
});
var rowCity = ko.utils.arrayFirst(rowCountry.Cities, function (city) {
return city.ID == row.City;
});
return new Location(rowRegion, rowCountry, rowCity);
}));
// Operations
self.addLine = function () {
self.lines.push(new Location())
};
self.removeLine = function (line) {
self.lines.remove(line)
};
};
var lvm = new LocationViewModel(existingRows);
$(function () {
ko.applyBindings(lvm);
});
HTML代码:
<tbody data-bind="foreach: lines">
<tr>
<td><select data-bind="options: newData, optionsText: 'Name', optionsValue: 'ID', optionsCaption: 'Select a region...', attr: { name: 'SubRegionIndex' + '['+$index()+']' }, value: region"></select></td>
<td><select data-bind="options: Countries, optionsText: 'Name', optionsValue: 'ID', optionsCaption: 'Select a country...', attr: { name: 'CountryIndex' + '['+$index()+']' }, value: country"></select></td>
<td><select data-bind="options: Cities, optionsText: 'Name', optionsValue: 'ID', optionsCaption: 'Select a city...', attr: { name: 'CityIndex' + '['+$index()+']' }, value: city"></select></td>
<td><a href='#' data-bind='click: $parent.removeLine'>Remove</a></td>
</tr>
</tbody>
我尝试使用预先填充的数据修改knockout.js网站上的购物车编辑器示例,但实际上没有取得多大进展,我似乎错过了一些东西。 没有真正找到嵌套数组的东西所以我被困在这里......
我在这里提出了JSFiddle的完整代码: http : //jsfiddle.net/fgXA2/1/
任何帮助,将不胜感激。
问题是您绑定到选择列表中所选项目的方式:
<select data-bind="
options: newData,
optionsText: 'Name',
optionsValue: 'ID',
value: region">
</select>
在这里,您将ID
属性从JSON数据绑定到视图模型上的region
属性。
这意味着当您绑定第二个选择列表时:
<td data-bind="with: region">
<select data-bind="
options: Countries,
optionsText: 'Name',
optionsValue: 'ID',
value: $parent.country">
</select>
</td>
您尝试绑定到region.Countries
。 但是, region
只包含所选的区域ID
。 在这种情况下,控制台是你的朋友:
未捕获错误:无法解析绑定。 消息:ReferenceError:未定义国家/地区;
您的第三个城市选择列表也存在同样的问题,因为您现在正尝试绑定到country.Cities
,其中country
也只是ID
。
这里有两个选项。 第一种是删除optionsValue
参数,从而将实际的 JSON对象绑定到视图模型属性。 那个和你的城市选择框上的绑定错误(你绑定到CityName
而不是Name
)是唯一的问题:
http://jsfiddle.net/benfosterdev/wHtRZ/
从示例中我可以看到,我使用了ko.toJSON
实用程序来输出视图模型的对象图。 这在解决问题时非常有用(在您的情况下,您会看到region
属性只是一个数字)。
上述方法的缺点是,您最终会在视图模型中存储所有国家/地区的副本以及所选国家/地区的城市。
如果处理大型数据集,则更好的解决方案是仅存储选定的标识符(我相信您最初尝试这样做),然后定义过滤单个数据集以获取所需值的计算属性。
可以在http://jsfiddle.net/benfosterdev/Bbbt3上看到此示例,使用以下计算属性:
var getById = function (items, id) {
return ko.utils.arrayFirst(items, function (item) {
return item.ID === id;
});
};
this.countries = ko.computed(function () {
var region = getById(this.selectedRegion.regions, this.selectedRegion());
return region ? ko.utils.arrayMap(region.Countries, function (item) {
return {
ID: item.ID,
Name: item.Name
};
}) : [];
}, this);
this.cities = ko.computed(function () {
var region = getById(this.selectedRegion.regions, this.selectedRegion());
if (region) {
var country = getById(region.Countries, this.selectedCountry());
if (country) {
return country.Cities;
}
}
}, this);
您可以从渲染对象图中看到,只有当前选定的国家/地区和城市被复制到视图模型中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.