我正在使用带有localstorage-adaper.js的ember.js。
我的问题始于一个已经回答的问题:EmberJS - record with hasMany relation fails to load
所以有模特:
// Models
App.List = DS.Model.extend({
name: DS.attr('string'),
items: DS.hasMany('item')
});
App.Item = DS.Model.extend({
name: DS.attr('string') ,
list: DS.belongsTo('list')
});
当#/ list / 1模板被渲染时,页面上没有显示这些项目,并且在控制台中抛出了断言失败:
Assertion failed: You looked up the 'items' relationship on 'App.List:ember236:1' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (DS.attr({ async: true }))
根据规定,解决方案是使hasMany async像这样:
App.List = DS.Model.extend({
name: DS.attr('string'),
items: DS.hasMany('item',{async:true})
});
它非常适合这种情况!
下一步:
我正在从服务器加载数据并在应用程序首次加载时将其推送到商店:(您可以在此处找到示例的JSBin:http://jsbin.com/lejizo/1/)
var data = { //in real life this is fetched through an AJAX request
'list': { id: '1', name: 'The List', items: ['1','2'] },
'items': {
'1': { id: '1', name: 'item 1', list: '1' },
'2': { id: '2', name: 'item 2', list: '1' }
}
};
...
this.store.push('list', data.list).save();
this.store.pushMany('item', data.items).forEach(function (item) {
item.save();
});
设置async:true选项后,我注意到item ID不再存在于localstorage中。 JSON看起来像这样:
{"App.List":{"records":{"1":{"id":"1","name":"The List","items":[]}}},"App.Item":{"records":{}}}
显然这些项目没有显示,因为没有参考。
我可能会认为我应该找到另一种方法来填充locastorage!怎么样?
或者这种情况还有另一种解决方法吗?
答案 0 :(得分:1)
在aync:true
关系旁边的hasMany
关系中,外键没有被持久保存到本地区域,这也会导致控制器内部出现其他问题。你得到的是Promise,而不是实际的对象,所以你总是必须使用list.get('items').then(/*code here*/)
(查看我发布的Ember local-storage How to use hasMany with async: true in controllers?这个问题),在某些情况下,你在循环中使用它可能会导致计算器。
使用localstorage,您将始终拥有客户端的所有数据。使用async是真的没有意义:true。问题是,ember需要list.items
的一组vanilla对象,而不仅仅是id。这里描述DS.FixtureAdapter loses fixture data with hasMany async attributes
有一种简单的解决方法可以摆脱async:true
关系中的hasMany
。请注意,您在localstorage中拥有所有需要的数据!如果Ember看到内存存储区中的项目,则不再抛出:"Assertion failed: You looked up the 'items' relationship on 'App.List:ember236:1' but some of the associated records were not loaded..."
错误。
解决方案:
Ember.Route.reopen({
beforeModel: function(transition){
this.store.find('list');
this.store.find('items');
}
});
我们覆盖Ember.Route
对象,因此我们在beforeModel
挂钩中调用store.find('object')
。这样做迫使Ember将数据从localstorage加载到“in memory”存储中!您将不再需要async:true
,也不会抛出任何错误。此外,在第一次初始化时,外键也将被保留!
每次都必须这样做(在Route超级类中),因为你永远不知道刷新将在哪条路径上发生。此外,对于具有多达50个记录的~10个型号的商店,它在~50-70ms内运行。如果在您的方案中看起来很多,请确保仅在您想要的路线上进行此呼叫,并且仅针对所需的模型。
此外,如果您覆盖路线中的beforeModel
,请务必致电
this._super(transition)
希望这有帮助!
答案 1 :(得分:0)
您错误地定义了数据,请尝试以下操作:
var data = { //in real life this is fetched through an AJAX request
'list': { id: '1', name: 'The List', items: [1,2] },
'items': [
{ id: '1', name: 'item 1', list: '1' },
{ id: '2', name: 'item 2', list: '1' }
}];
}
首先,您的物品前面不需要索引1,2,.... 第二个hasMany关系应该返回一个数组,这就是items将数据包装为数组的原因。 因此,要解决您的问题,您必须修复服务器中的数据,或编写序列化程序来按摩数据。
希望它有所帮助!