8

我有一个DS.Store使用DS.RESTAdapter和 一个ChatMessage这样定义的对象:

App.ChatMessage = DS.Model.extend({
    contents: DS.attr('string'),
    roomId:   DS.attr('string')
});

请注意,聊天消息存在于房间中(为简单起见未显示),因此在我的聊天消息控制器(扩展Ember.ArrayController)中,我只想为用户当前所在的房间加载消息:

loadMessages: function(){ 
    var room_id = App.getPath("current_room.id");
    this.set("content", App.store.find(App.ChatMessage, {room_id: room_id}); 
}

这会将 设置content为 aDS.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 请求以将消息保存在服务器上,到目前为止一切正常,但它不会更新视图。这很有意义,因为它是过滤后的结果,如果我删除 room_id 过滤器App.store.find那么它会按预期更新。

尝试this.pushObject(message)使用从返回的消息记录App.store.createRecord会引发错误。

如何手动将项目添加到结果中?据我所知,似乎没有一种方法,因为两者DS.AdapterPopulatedModelArray都是DS.FilteredModelArray不可变的。

4

4 回答 4

8

所以有几个想法:

(参考: https ://github.com/emberjs/data/issues/190 )

如何侦听数据存储区中的新记录

一个普通的 Model.find()/findQuery() 将返回一个 AdapterPopulatedModelArray,但该数组将独立存在......它不会知道任何新内容已加载到数据库中

没有参数的 Model.find()(或 store.findAll())将返回所有记录 FilteredModelArray,并且 ember-data 会将其“注册”到列表中,并且加载到数据库中的任何新记录都将添加到这个数组。

调用 Model.filter(func) 会给你一个 FilteredModelArray,它也在存储中注册......并且存储中的任何新记录都会导致 ember-data 为“updateModelArrays”,这意味着它将调用你的过滤器函数新记录,如果您返回true,那么它会将其粘贴到您现有的数组中。

所以我最终做了什么:在创建商店后立即调用 store.findAll(),它为我返回了一个类型的所有模型的数组……然后我将它附加到商店……然后在其他任何地方在代码中,我可以将ArrayObservers 添加到这些列表中......类似于:

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) {}
})

如何将模型推入这些“不可变”数组之一:

首先要注意:所有 Ember-Data 模型实例(记录)都有一个 clientId 属性...这是一个唯一的整数,用于标识数据存储缓存中的模型,无论它是否具有真实的服务器 ID(例如:在做之后一个 Model.createRecord)。

所以 AdapterPopulatedModelArray 本身有一个“内容”属性...这是这些 clientId 的数组...当您遍历 AdapterPopulatedModelArray 时,迭代器会遍历这些 clientId 并将映射的完整模型实例(记录)交还给您给每个clientId。

所以我 所做的(这并不意味着它是“正确的”!)是观察那些 findAll 数组,并将新的 clientId 推送到 AdapterPopulatedModelArray 的 content 属性中......类似的东西:

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 更新时中断吗?完全有可能

于 2012-04-18T20:36:16.053 回答
2

对于那些仍在为此苦苦挣扎的人,您可以使用store.filter方法让自己成为动态DS.FilteredArray的而不是静态的。它需要 3 个参数:类型、查询和最后一个过滤器回调。DS.AdapterPopulatedRecordArray

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;
  });
}
于 2013-10-02T07:54:53.387 回答
0

我对源代码 (DS.Store.find) 的阅读表明,您在此实例中实际收到的是一个 AdapterPopulatedModelArray。当您创建记录时,FilteredModelArray 会自动更新。有针对这种行为的通过测试。

于 2012-04-08T17:30:18.653 回答
0

从 ember.data 1.13store.filter开始,标记为删除,请参阅以下ember 博客文章

该功能以 mixin 的形式提供。GitHub 页面包含以下注释

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

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

于 2018-05-06T07:14:05.460 回答