4

私は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を含む)およびCountriesサブ配列(Countries'Citiesを含む)へのアクセスに問題があるため、データを適切にロードできない(またはより明確にバインドする)ことができないと思われます。 。

次に、事前に入力されたオプションがあるという問題があります。これは部分的に機能し、ビューモデルは行数をロードしますが、何も選択しません。

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 Webサイトのカートエディターの例を変更しようとしましたが、あまり進歩しておらず、何かが足りないようです。ネストされた配列では実際には何も見つからなかったので、ここで立ち往生しています...

私はここでJSFiddleに完全なコードを載せました:http: //jsfiddle.net/fgXA2/1/

どんな助けでもいただければ幸いです。

4

1 に答える 1

5

問題は、選択リストで選択したアイテムにバインドする方法です。

<select data-bind="
    options: newData, 
    optionsText: 'Name', 
    optionsValue: 'ID', 
    value: region">
</select>

IDここでは、JSONデータのregionプロパティをビューモデルのプロパティにバインドしています。

これは、2番目の選択リストをバインドするときに次のことを意味します。

<td data-bind="with: region">
    <select data-bind="
        options: Countries, 
        optionsText: 'Name', 
        optionsValue: 'ID', 
        value: $parent.country">
    </select>
</td>

にバインドしようとしましたregion.Countries。ただし、region選択した領域が含まれているだけですID。この場合、コンソールはあなたの友達です:

キャッチされないエラー:バインディングを解析できません。メッセージ:ReferenceError:国が定義されていません。

同じ問題は、都市の3番目の選択リストにも当てはまります。これは、現在、がcountry.Citiesである場所にバインドしようとしているためcountryですID

ここでは2つのオプションを利用できます。optionsValue1つ目は、パラメーターを削除して、実際の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);

レンダリングされたオブジェクトグラフから、現在選択されている国と都市のみがビューモデルにコピーされていることがわかります。

于 2013-01-27T20:56:11.230 に答える