我有DS.Store
使用DS.RESTAdapter
和ChatMessage
对象定义如下:
App.ChatMessage = DS.Model.extend({
contents: DS.attr('string'),
roomId: DS.attr('string')
});
请注意,房间中存在聊天消息(为简单起见未显示),因此在我的聊天消息控制器(扩展Ember.ArrayController
)中,我只想为用户当前所在的房间加载消息: / p>
loadMessages: function(){
var room_id = App.getPath("current_room.id");
this.set("content", App.store.find(App.ChatMessage, {room_id: room_id});
}
这会将content
设置为DS.AdapterPopulatedModelArray
,我的视图会愉快地显示{{#each}}
块中返回的所有聊天消息。
现在要添加一条新消息,我在同一个控制器中有以下内容:
postMessage: function(contents) {
var room_id = App.getPath("current_room.id");
App.store.createRecord(App.ChatMessage, {
contents: contents,
room_id: room_id
});
App.store.commit();
}
这会启动ajax请求以在服务器上保存消息,到目前为止一切都很好,但它不会更新视图。这非常有意义,因为它是一个过滤结果,如果我删除了App.store.find
上的room_id过滤器,那么它会按预期更新。
使用this.pushObject(message)
返回的消息记录尝试App.store.createRecord
会引发错误。
如何手动将项目添加到结果中?由于DS.AdapterPopulatedModelArray
和DS.FilteredModelArray
都是不可变的,所以似乎没有办法。
答案 0 :(得分:8)
有几点想法:
(参考:https://github.com/emberjs/data/issues/190)
如何监听数据存储区中的新记录
正常的Model.find()/ findQuery()将返回一个AdapterPopulatedModelArray,但该数组将独立存在......它不会知道任何新的已加载到数据库中
没有params(或store.findAll())的Model.find()将返回所有记录FilteredModelArray,而ember-data将"注册"将其添加到列表中,并将加载到数据库中的任何新记录添加到此数组中。
调用Model.filter(func)将返回一个FilteredModelArray,它也在商店中注册...并且商店中的任何新记录都会导致ember-data到" updateModelArrays&#34 ;,含义它会使用新记录调用您的过滤器功能,如果您返回 true ,它会将其粘贴到您现有的数组中。
那我结束了什么:在创建商店之后,我立即调用了store.findAll(),它给了我一个类型的所有模型的数组......然后我将它附加到商店......然后在代码中的任何其他地方,我可以将ArrayArrayObservers添加到这些列表中。例如:
App.MyModel = DS.Model.extend()
App.store = DS.Store.create()
App.store.allMyModels = App.store.findAll(App.MyModel)
//some other place in the app... a list controller perhaps
App.store.allMyModels.addArrayObserver({
arrayWillChange: function(arr, start, removeCount, addCount) {}
arrayDidChange: function(arr, start, removeCount, addCount) {}
})
如何将模型推入其中一个" immutable"阵列强>
首先要注意:所有Ember-Data Model实例(记录)都有一个clientId属性...这是一个唯一的整数,用于标识数据存储区缓存中的模型,无论它是否具有 real server-id(例如:在做一个Model.createRecord之后)。
所以AdapterPopulatedModelArray本身有一个"内容" property ...这是clientId的一个数组...当你遍历AdapterPopulatedModelArray时,迭代器遍历这些clientId并传递给映射到的完整模型实例(记录)每个clientId。
我做了什么 (这并不代表它"对"!)是观察那些findAll数组,并将新的clientId推送到AdapterPopulatedModelArray的content属性中... SOMETHING LIKE :
arrayDidChange:function(arr, start, removeCount, addCount){
if (addCount == 0) {return;} //only care about adds right now... not removes...
arr.slice(start, start+addCount).forEach(function(item) {
//push clientId of this item into AdapterPopulatedModelArray content list
self.getPath('list.content').pushObject(item.get('clientId'));
});
}
我能说的是:"它为我工作" :)它会破坏下一个ember-data更新吗?完全可能
答案 1 :(得分:2)
对于那些仍在努力解决此问题的人,您可以使用 store.filter 方法为自己提供动态DS.FilteredArray
而不是静态DS.AdapterPopulatedRecordArray
。它takes 3 parameters:输入,查询,最后是过滤回调。
loadMessages: function() {
var self = this,
room_id = App.getPath('current_room.id');
this.store.filter(App.ChatMessage, {room_id: room_id}, function (msg) {
return msg.get('roomId') === room_id;
})
// set content only after promise has resolved
.then(function (messages) {
self.set('content', messages);
});
}
您也可以在模型挂钩中执行此操作而不会产生额外的混乱,因为模型挂钩将直接接受承诺:
model: function() {
var self = this,
room_id = App.getPath("current_room.id");
return this.store.filter(App.ChatMessage, {room_id: room_id}, function (msg) {
return msg.get('roomId') === room_id;
});
}
答案 2 :(得分:0)
我对源代码的阅读(DS.Store.find)显示,您在此实例中实际接收的是AdapterPopulatedModelArray。 FilteredModelArray会在您创建记录时自动更新。有这种行为的通过测试。
答案 3 :(得分:0)
自ember.data 1.13 store.filter
标记为删除后,请参阅以下ember blog post。
该功能已提供as a mixin。 GitHub页面包含以下注释
我们建议您重构以免使用此插件。下面是三个过滤器使用场景的简短指南,以及如何最好地重构每个场景。
为什么呢?简而言之,您可以通过专门为您的需求量身定制的专用计算属性来管理过滤,从而提高性能(而不是内存泄漏)