簡體   English   中英

knockout.js - 嵌套數組數據和級聯預填充下拉列表綁定

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM