我正在使用带有本地存储适配器的ember.js
以下是一个带有此问题的JSbin:http://jsbin.com/lejizo/9/edit?html,控制台,输出
拥有以下型号:
/* Models */
App.List = DS.Model.extend({
name: DS.attr('string'),
// DOES NOT WORK:: items: DS.hasMany('item')
items: DS.hasMany('item', {async: true})
});
App.Item = DS.Model.extend({
name: DS.attr('string'),
list: DS.belongsTo('list')
});
如果不使hasMany
异步,Ember数据将抛出错误。顺便说一下,数据在localstoarge
中。我这样初始化它:
var FIXTURES = {
'list': {
records: {
'1': {
id: '1',
name: 'The List',
items: ['1','2']
},
'2': {
id: '2',
name: 'The Second List',
items: ['1','3']
}
}
},
'item': {
records: {
'1': {
id: '1',
name: 'item 1',
list: '1' },
'2': {
id: '2',
name: 'item 2',
list: '1'
},
'3': {
id: '3',
name: 'item 3',
list: '1'
}
}
}
}
localStorage.setItem('DS.LSAdapter', JSON.stringify(FIXTURES));
无论如何,使items: DS.hasMany('item', {async: true})
可以使应用程序顺利运行。
问题是,如果我试图从控制器访问items
,它们不是一个对象,它们只是一个承诺!这迫使我们使用以下方法:
list.get('items').then(function(items) { // must use then
items.forEach(function(item){
console.log(item.get('id'));
});
});
这对我来说似乎很尴尬,总是要注意hasMany
关系,并小心如何使用它们,而不是像处理任何其他关系那样只处理相关对象。。
这是正常的还是我错过了什么?有没有一种变通方法可以不将它们定义为async:true,因为所有数据都已经在本地存储中了?我们是否应该始终使用所有相关实体的then-in控制器作为最佳实践?
这对我来说似乎很尴尬,总是要注意hasMany关系,并小心如何使用它们,而不是像处理任何其他关系那样只处理相关对象。。
那会很尴尬,这就是为什么你不必这么做的原因。)在大多数情况下,Ember会自动监视属性更新并相应地传播它们。这是什么意思?这意味着你不应该担心价值是一个承诺使用它,就好像它不是一个。
简言之,Ember使用了一种特殊的承诺来关注房产更新。假设您有以下模板:
{{#each item in model.items}}
{{item.name}}
{{/each}}
如果model.items
是一个异步的hasMany
关系,Ember仍然会做正确的事情。当模板第一次渲染时,将没有数据您的each
循环不会产生任何结果但是Ember会关注model.items
属性的更新。当它有更新时(比如当promise解析时),Ember将再次运行模板。这一次,数据将在那里,它将完全按照您的期望工作。
属性也是如此:
function() {
return this.get('model.items').filter(function(item) {
return !!item;
});
}.property('model.items.@each')
此属性在第一次运行时将返回一个空数组。但是,当承诺得到解决时,Ember将再次运行该属性并生成您想要的结果。
在这背后有很多事情要做,但在进入一些更复杂的用例之前,您通常不需要担心。如果你想了解更多,我建议你查看这些资源:
- RSVP Promise库
- Ember异步指南
- ObjectProxy和ArrayProxy类
- PromiseProxy Mixin类
编辑:如果你想修改关系,例如,添加一个新项目,可以这样做:
actions: {
addPost: function(post) {
this.get('model.posts').then(function(posts) {
posts.addObject(post);
});
}
}