【发布时间】:2014-06-06 01:51:51
【问题描述】:
环境
# Ember : 1.4.0
# Ember Data : 1.0.0-beta.7+canary.b45e23ba
型号
我已经简化了我的用例,使问题更容易理解和回答。假设我们有 3 个模型:Country、Region 和 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')
预期结果
Route 的模型钩子应该返回一个对象数组。像这样:
注意:缩进仅是为了使示例更具可读性。
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 并观看this talk,但是我有点未能创建正确的代码来链接承诺,并在最终then 修改返回的结果以匹配我的期望。
最后的想法
有人告诉我,像这样加载数据可能会导致许多 HTTP 请求,这可能会通过旁加载更好地解决,但是:
- 此时,我使用
FixturesAdapter,所以 HTTP 请求不是问题 - 我真的很想更好地理解 RSVP 和 Promises
这就是为什么弄清楚应该如何正确完成这件事对我来说很重要。
编辑 1:应用kingpin2k 建议的更改
我为我的示例创建了一个JSBin,其中包含 kingpin2k 的 anwser 建议的更改。
虽然代码有效,但结果... 出乎意料:
- 在
countries数组中,我找到了country和region对象。 为什么? -
country和region对象似乎已加载,但区域没有加载(请参阅 JSBin 中的控制台日志结果).. 为什么?
编辑 2:对来自 Edit1 的意外行为的解释。
所以我终于注意到我从 Ember 的正义之路误入歧途了。 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! 中的工作解决方案!
【问题讨论】:
标签: javascript ember.js ember-data rsvp-promise