将项添加到来自ember-data的过滤结果中

时间:2012-04-03 16:38:31

标签: ember.js ember-data

我有DS.Store使用DS.RESTAdapterChatMessage对象定义如下:

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.AdapterPopulatedModelArrayDS.FilteredModelArray都是不可变的,所以似乎没有办法。

4 个答案:

答案 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页面包含以下注释

  

我们建议您重构以免使用此插件。下面是三个过滤器使用场景的简短指南,以及如何最好地重构每个场景。

     

为什么呢?简而言之,您可以通过专门为您的需求量身定制的专用计算属性来管理过滤,从而提高性能(而不是内存泄漏)