8

環境

# Ember       : 1.4.0
# Ember Data  : 1.0.0-beta.7+canary.b45e23ba

モデル

質問を理解しやすくするために、ユースケースを単純化しました。CountryRegionおよびの 3 つのモデルがあるとしAreaます。

Country:
  - id: DS.attr('number')
  - name: DS.attr('string')
  - regions: DS.hasMany('region')

Region:
  - id: DS.attr('number')
  - name: DS.attr('string')
  - country: DS.belongsTo('country')
  - areas: DS.hasMany('area')

Area:
  - id: DS.attr('number')
  - name: DS.attr('string')
  - region: DS.belongsTo('region')

予想された結果

ルートのモデル フックは、オブジェクトの配列を返す必要があります。このような:

注:インデントは、例を読みやすくするためだけのものです。

 Country I
   Region A
      Area 1
      Area 2
   Region B
      Area 3
 Country II
   Region C
      Area 4
 Country III
   Region D
      Area 5

現在のアプローチ

App.MyRoute = Ember.Route.extend({
  model: function() {
    return this.store.find('country').then(function(countries){
      // promise all counties

      // map resolved countires into an array of promises for owned regions
      var regions = countries.map(function(country){
        return country.get('regions');
      });

      // map resolved regions into an array of promises for owned areas
      var areas = regions.then(function(regions){
        return regions.map(function(region){
          return region.get('areas');
        });
      });

      // do not return until ALL promises are resolved
      return Ember.RSVP.all(countries, regions, areas).then(function(data){
        // here somehow transform the data into expected output format and return it
      });
    });
  }
)};

エラー

私はError while loading route: TypeError: Object [object Array] has no method 'then'明らかにこのコードに由来するものを取得しています:

var regions = countries.map(function(country){
  return country.get('regions');
});
var areas = regions.then(function(regions){
// regions is not a promise

ただし、これは私が抱えている本当の問題を示しているはずです:

問題

countriesを取得するために解決する必要がregionsあり、次に を取得する必要がありareasます。RSVP.hash関数とRSVP.all関数をチェックし、公式 API を読み、このトークを見てきましたが、promise をチェーンするための正しいコードを作成できず、最終的thenに返された結果を期待どおりに変更することができませんでした。

最終的な考え

このようなデータをロードすると、多くの HTTP リクエストが発生する可能性があり、おそらくこれはサイドローディングによってより適切に解決されると言われていますが、次のようになります。

  • 現時点では を使用FixturesAdapterしているため、HTTP リクエストは問題になりません
  • RSVP と Promises をもっとよく理解したい

そのため、これを正しく行う方法を理解することが重要です。

編集 1: kingpin2kによって提案された変更の適用

kingpin2k の anwser によって提案された変更を加えて、私の例のJSBinを作成しました。

コードは機能しますが、結果は...予期しないものです:

  • countries配列でcountryregionオブジェクトの両方を見つけました。なんで?
  • countryおよびオブジェクトはロードされているように見えますが、エリアはロードされていませregion(JSBin のコンソール ログの結果を参照してください)。

編集 2: Edit1 からの予期しない動作の説明。

ということで、エンバーの正道から外れていたところにようやく気がつきました。Kingpin2k の anwser は大きな前進でしたが、小さなエラーが含まれています。

return this.store.find('country').then(function(countries){
  // this does not return an array of regions, but an array of region SETs
  var regionPromises = countries.getEach('regions');

  // wait for regions to resolve to get the areas
  return Ember.RSVP.all(regionPromises).then(function(regions){
    // thats why here the variable shouldn't be called "regions"
    // but "regionSets" to clearly indicate what it holds

    // for this example i'll just reassign it to new var name
    var regionSets = regions;

    // now compare these two lines (old code commented out)
    //var areaPromises = regions.getEach('areas'); 
    var areaPromises = regionSets.getEach('areas');

    // since regionSet does not have a property "areas" it
    // won't return a promise or ever resolve (it will be undefined)

    // the correct approach would be reduceing the array of sets
    // an array of regions
    var regionsArray = regionSets.reduce(function(sum, val){
      // since val is a "Ember.Set" object, we must use it's "toArray()" method
      // to get an array of contents and then push it to the resulting array
      return sum.pushObjects(val.toArray());
    }, []);

    // NOW we can get "areas"
    var realAreaPromises = regionsArray.getEach('areas');

    // and now we can use Ember.RSVP to wait for them to resolve
    return Ember.RSVP.all(realAreaPromises).then(function(areaSets){
    // note: here again, we don't get an array of areas
    // we get an array of area sets - each set for the corresponding region
      var results = [];

だから..今、私は最終的にすべてのオブジェクト(国、地域、地域)を正しく解決し、仕事を続けることができます:)

編集 3: このJSBinの作業ソリューション!

4

2 に答える 2