[英]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.