# 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,但是我有点无法创建正确的代码来链接承诺和最终{{1}修改返回的结果以符合我的期望。
我被告知加载这样的数据可能会导致很多HTTP请求,这可能会通过sideloading更好地解决,但是:
then
,因此HTTP请求不是问题这就是为什么我要弄清楚如何正确地做到这一点很重要。
我为我的例子创建了一个JSBin,其中包含了由kingpin2k的anwser建议的更改。
虽然代码有效,但结果是...... 意外:
FixturesAdapter
数组中我找到了countries
和country
个对象。的为什么吗
region
和country
对象似乎已加载,但区域不加载(请参阅JSBin中的控制台日志结果).. 为什么? 所以我终于注意到我从Ember的正义道路误入歧途。 Kingpin2k的anwser向前迈出了一大步,但它包含一点错误:
region
所以..现在我终于正确地解决了所有对象(国家,地区,地区),并且可以继续我的工作:)
答案 0 :(得分:12)
诀窍是,您需要先解决某些承诺,然后才能访问这些记录上的属性。 Ember.RSVP.all
采用一系列承诺。 Ember.RSVP.hash
接受了承诺。不幸的是,在你之前的承诺得到解决之前,你无法构建你的承诺(la,你不知道在regions
解决之前得到哪个countries
,而你在areas
被解决之前,不知道要获得哪个regions
。在这种情况下,你真的有一系列的承诺来获取(尽管每个级别的承诺数组)。 Ember知道要等到最深的承诺得到解决并将该值用作模型。
现在我们需要假装regions
和area
是异步的,如果不是,你告诉Ember Data,信息将包含在country
的请求中,或者在region
的请求中,这些集合不会是承诺,因此下面包含的代码不起作用。
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;
});
});
});
}
});
所有这一切都说,因为看起来你正在使用Ember Data,我只返回this.store.find('country')
并让Ember Data在使用时获取数据......这个模板可以在没有所有承诺的情况下工作代码,并将填充为Ember Data履行其自己的承诺(一旦它看到你试图使用数据,它将请求数据,好的延迟加载)。
{{#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}}
答案 1 :(得分:4)
如果你在这里,你可能会犯同样的错误:)
如果您需要一个复杂的对象树来显示您的路线,您还可以:
this.store.find('mymodel', model_id)
然而,我将原来的anwser标记为"接受"因为它实际上是原始问题的答案,而这个anwser只是一个未来参考/其他用户的注释。