How to return a promise composed of nested models in EmberJS with EmberData?

安稳与你 提交于 2019-11-30 07:14:32

The trick is you need to resolve certain promises before you can access the properties on those records. Ember.RSVP.all takes an Array of promises. Ember.RSVP.hash takes a hash of promises. Unfortunately you're in the situation where you can't construct your promises until the previous promises have resolved (a la, you don't know which regions to get until the countries are resolved, and you don't know which areas to get until the regions are resolved). That being the case you really have a serial set of promises to fetch (albeit arrays of promises at each level). Ember knows to wait until the deepest promise has resolved and to use that value as the model.

Now we need to pretend that regions and area are async, if they aren't, you're telling Ember Data the information will be included in the request with country, or in the request with region and those collections won't be promises so the code I've included below wouldn't work.

regions: DS.hasMany('region', {async: true})

areas: DS.hasMany('area', {async: true})

App.IndexRoute = Ember.Route.extend({
  controllerName: 'application',

  model: function() {
    return this.store.find('country').then(function(countries){
      // get each country promises
      var regionCollectionPromises = countries.getEach('regions');

      // wait for regions to resolve to get the areas
      return Ember.RSVP.all(regionCollectionPromises).then(function(regionCollections){

        var regions = regionCollections.reduce(function(sum, val){
            return sum.pushObjects(val.toArray());
        }, []);

        var areaCollectionPromises = regions.getEach('areas');
        //wait on the areas to resolve
        return Ember.RSVP.all(areaCollectionPromises).then(function(areaCollections){

          // yay, we have countries, regions, and areas resolved

          return countries;
        });
      });
    });

  }
});

All this being said, since it appears you're using Ember Data, I'd just return this.store.find('country') and let Ember Data fetch the data when it's used... This template would work without all of that promise code, and would populate as Ember Data fulfill's the promises on its own (it will request the data once it sees you've attempted to use the data, good ol' lazy loading).

{{#each country in model}}
  Country: {{country.name}}
  {{#each region in country.regions}}
    Region: {{region.name}}
      {{#each area in region.areas}}
        Area: {{area.name}}
     {{/each}}
  {{/each}}
{{/each}}

What you could do instead:

If you're here, you're probably doing the same mistake as I did :)

If you need a complicated tree of objects to display your route, you could also:

  • If you use RESTAdapter you could sideload data in one HTTP request.
  • If you use FixturesAdapter (eg. in development phase) with a fixed set of data, you could switch to LocalStorageAdapter - as when you request a model, it loads all the associated models. So it will be as easy as a simple this.store.find('mymodel', model_id)

However I'm leaving the original anwser marked as "accepted" as it actually anwsers the original question, and this anwser is just a note for future reference/other users.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!