将骨干集合与服务器响应合并

Jor*_*eña 6 coffeescript backbone.js

TL; DR:如果我从服务器轮询整个模型集合,如何将更改的属性合并到每个模型中,并从集合中添加/删除添加/删除的模型?

在我的骨干应用程序中,我正在轮询整个模型集合.我有一个Backbone.Collection我基本上reset每次得到模型数组时都会调用,所以:

myCollection.reset(server_response);
Run Code Online (Sandbox Code Playgroud)

唯一的问题是它摆脱了旧模型,消除了模型上事件的好处.这reset当然是目的,但我想要做的只是修改模型的已更改属性,并删除不在响应中的模型,并添加响应中但不是集合的模型.

基本上我想要一种数据合并.

对于已经在响应中和集合中的模型,我相信我可以这样做model.set(attributes),它只set处理实际更改的模型,触发change流程中的事件.这很棒.

但是,我如何处理模型在响应中但不在集合中的情况,反之亦然,不是在响应中而是在集合中?

我建议的解决方案

我不知道骨干是否已经有办法做到这一点,我可能会过度复杂,这就是为什么我要问,但我当时正在考虑在我的集合上创建一个方法来传递server_response.

它会得到所有的id属性server_response,以及所有id模型的属性已经在收集.

id响应中的差异- 收集将=添加模型,反之亦然将被移除模型.分别从集合中添加和删除这些模型.

两组的交集id将是修改后的模型,所以迭代这些id并简单地做一个collection.get(id).set(attributes).

在pseudocoffeescript中:

merge: (server_response) =>
  response_ids = _.pluck(server_response, 'id')
  collection_ids = @pluck('id')

  added = _.difference(response_ids, collection_ids)

  for add in added
    @add(_.find(server_response, (model) ->
      return model.id == add
    ))

  removed = _.difference(collection_ids, response_ids)

  for remove in removed
    @remove(@get(remove))

  changed = _.intersection(response_ids, collection_ids)

  for change in changed
    @get(change).set(_.find(server_response, (model) ->
      return model.id == change
    ))
Run Code Online (Sandbox Code Playgroud)

max*_*0rd 9

这种技术有时很有用.我们使用以下方法扩展Collection.这应该做你想要的.它不是咖啡,但你可以轻松移植它.请享用!

// Take an array of raw objects
// If the ID matches a model in the collection, set that model
// If the ID is not found in the collection, add it
// If a model in the collection is no longer available, remove it
freshen: function (objects) {
    var model;
    // Mark all for removal

    this.each(function (m) {
        m._remove = true;
    });

    // Apply each object
    _(objects).each(function (attrs) {
        model = this.get(attrs.id);
        if (model) {
            model.set(attrs); // existing model
            delete model._remove
        } else {
            this.add(attrs); // new model
        }
    }, this);

    // Now check for any that are still marked for removal
    var toRemove = this.filter(function (m) {
        return m._remove;
    })

    _(toRemove).each(function (m) {
        this.remove(m);
    }, this);
    this.trigger('freshen', this);
}
Run Code Online (Sandbox Code Playgroud)