2011-11-21 63 views
6

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

在我的骨干应用程序中,我正在轮询整个模型集合。我有一个Backbone.Collection,我基本上每次都在呼吁reset我得到的车型阵列,所以:

myCollection.reset(server_response); 

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

本质上我想要一种合并的数据。

对于模型是在响应和收集已经在,我相信我可以做model.set(attributes),它需要照顾set荷兰国际集团只有实际改变的,触发的过程中change事件。这很棒。

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

我所提出的解决方案

我不知道,如果骨干已经有这样做的方式,我可能会过于复杂这就是为什么我问,但我想创建一个方法,然后在我的收藏中获得通过server_response

它将获得server_response的所有id属性以及集合中已有模型的所有id属性。

id在回应中的差异 - 集合会=添加模型,反之亦然将被删除模型。从集合中分别添加和删除这些模型。

两组id的交集都是修改后的模型,所以遍历这些id's并简单地做一个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 
    )) 
+0

*>在pseudocoffeescript:*哦,上帝。 –

+0

它实际上是coffeescript,我的意思是伪造的,因为我还没有测试它,但哈哈。 –

回答

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); 
} 
+0

酷感谢maxl0rd。似乎与我去过的相似,但我可以从中使用一些东西,例如remove标志。我会稍微等一下,看看是否有其他答案弹出,否则我会将你的标记为正确的:) –

+0

良好的交易。 “标记和扫描”有点难看,但可能是大型馆藏最有效的方法。 – maxl0rd

+0

非常酷和有用的感谢。我添加了一些细微的变化,以保留本地增加的集合并保留客户端的任何状态。你可能会喜欢这个改变。 只需将'm._remove = true;'改为'if(!m.isNew())m._remove = true; – Subimage