Javascript knockout.js-嵌套数组数据和级联预填充下拉列表绑定
我对knockout.js还很陌生,但是,我一直很高兴地在我的ASP.NETMVC4项目中使用它,直到我遇到了这个困扰了我一段时间的障碍,我似乎无法找到它 我正在处理的场景需要几个位置数据组合(地区、国家、城市),即级联下拉列表,这在输入新数据时不是问题,但在尝试编辑保存的数据时遇到了问题 数据为JSON格式,带有嵌套数组,如下所示(为便于说明而缩短): 我怀疑我无法正确加载数据(或者更清楚地说,无法绑定它),因为我无法访问Region子数组(包含Region的国家)和Countries子数组(包含Countries的城市) 然后是预填充选项的问题,这部分起作用,viewmodel加载行数,但不选择任何内容 以下是虚拟机:Javascript knockout.js-嵌套数组数据和级联预填充下拉列表绑定,javascript,data-binding,knockout.js,cascadingdropdown,Javascript,Data Binding,Knockout.js,Cascadingdropdown,我对knockout.js还很陌生,但是,我一直很高兴地在我的ASP.NETMVC4项目中使用它,直到我遇到了这个困扰了我一段时间的障碍,我似乎无法找到它 我正在处理的场景需要几个位置数据组合(地区、国家、城市),即级联下拉列表,这在输入新数据时不是问题,但在尝试编辑保存的数据时遇到了问题 数据为JSON格式,带有嵌套数组,如下所示(为便于说明而缩短): 我怀疑我无法正确加载数据(或者更清楚地说,无法绑定它),因为我无法访问Region子数组(包含Region的国家)和Countries子数组(
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网站上的购物车编辑器示例,但没有取得多大进展,我似乎遗漏了一些东西。没有找到任何嵌套数组,所以我被困在这里
我在这里展示了JSFIDLE的完整代码:
任何帮助都将不胜感激。问题在于您绑定到选择列表中所选项目的方式:
<select data-bind="
options: newData,
optionsText: 'Name',
optionsValue: 'ID',
value: region">
</select>
您试图绑定到地区.国家/地区
。但是,region
仅包含所选区域ID
。在这种情况下,控制台是您的朋友:
未捕获错误:无法分析绑定。消息:ReferenceError:
国家没有定义
第三个城市选择列表也存在同样的问题,因为您现在正试图绑定到国家/地区。城市国家/地区也只是ID
这里有两种选择。第一个是删除选项value
参数,从而将实际的JSON对象绑定到视图模型属性。这和城市选择框上的绑定错误(您绑定到的是CityName
,而不是Name
)是唯一的问题:
从示例中可以看到,我使用ko.toJSON
实用程序输出视图模型的对象图。这在解决问题时非常有用(在您的例子中,您会看到区域
属性只是一个数字)
上述方法的缺点是,最终会在视图模型中存储选定国家的所有国家及其城市的副本
如果处理大型数据集,更好的解决方案是只存储选定的标识符(我相信您最初是尝试这样做的),然后定义计算属性,以过滤单个数据集的所需值
使用以下计算属性,可在中查看此示例:
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);
您可以从渲染的对象图中看到,只有当前选定的国家/地区和城市被复制到视图模型。感谢您提供的解决方案和调试指针!非常感谢。只是一个后续问题-当我向服务器提交表单时,我依赖optionsValue,因此我想我必须使用您的第二个建议作为最佳选项?回答我自己的问题-我遵循了您的第二个建议,并使用添加/删除行选项对其进行了扩展。效果很好。感谢您的启发:)如果您使用普通表单提交将数据发送到服务器,那么您需要设置选项value
参数。或者,您可以使用视图模型提交数据,在这种情况下,您可以完全控制发送的内容。
<td data-bind="with: region">
<select data-bind="
options: Countries,
optionsText: 'Name',
optionsValue: 'ID',
value: $parent.country">
</select>
</td>
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);