【问题标题】:Adding item to filtered result from ember-data将项目添加到来自 ember-data 的过滤结果
【发布时间】:2012-04-03 16:38:31
【问题描述】:

我有一个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 设置为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 过滤器,那么它会按预期更新。

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

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

【问题讨论】:

    标签: ember.js ember-data


    【解决方案1】:

    有几个想法:

    (参考: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 属性...这是一个唯一的整数,用于标识数据存储缓存中的模型,无论它是否具有 真实 server-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 更新时中断吗?完全有可能

    【讨论】:

      【解决方案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;
        });
      }
      

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • 你是对的,它是一个 AdapterPopulatedModelArray。我已经更新了问题 - 抱歉打错了!
        【解决方案4】:

        从 ember.data 1.13 开始,store.filter 被标记为删除,请参阅以下ember blog post

        该功能已提供as a mixin。 GitHub页面包含以下注释

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-04-04
          • 1970-01-01
          • 1970-01-01
          • 2019-10-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多