2012-09-05 62 views
10

我有一个Backbone集合,包含一系列模型。一次保存多个Backbone模型

每当一个特定的属性被设置在一个模型,它被保存,计算的负载断火和UI重新渲染。

但是,我希望能够一次设置多个模型的属性和只能做储蓄和重新描绘,一旦他们所有的设置。当然,我不想为一个操作发出多个http请求,并且肯定不希望重新渲染界面十次。

我希望能找到Backbone.Collection)保存方法,将工作哪些型号hasChanged(一起重击他们作为JSON和欢送到后端。然后可以通过集合上的事件触发重新呈现。没有这样的运气。

这似乎是一个很常见的需求,所以很奇怪,为什么骨干网没有实现。这是否违背RESTful体系结构,将几件事情保存到单个端点?如果是这样,那又如何?使1000个请求保留1000个小项目是不现实的。

那么,是唯一的解决方案,用我自己的save方法来增强Backbone.Collection,它遍历所有的模型,并为所有已更改的json构建json,并将其发送到后端?或者没有人有一个整洁的解决方案(或者我只是错过了一些东西!)?

+3

相关:http://stackoverflow.com/questions/11819662/why-does-backbone-not-have-a-save-put-post-method-for-its-collections-is-i/11819965#11819965 | http://stackoverflow.com/questions/11042292/extend-backbone-sync-to-batch-sync | http://stackoverflow.com/questions/511281/patterns-for-handling-batch-operations-in-rest-web-services | http://stackoverflow.com/questions/8529919/how-to-update-a-set-of-records-using-backbone-js-rails – fguillen

回答

4

我已经结束了用一些方法来处理这个问题,以增强Backbone.Collection。

的saveChangeMethod创建要传递给Backbone.sync一个假人模型。模型中所有主干的同步方法需求都是它的url属性和JSON方法,所以我们可以很容易地将其敲除。

在内部,模型的toJSON方法只返回其属性的副本(要发送到服务器),所以我们可以愉快地使用刚刚返回模型数组的toJSON方法。 Backbone.sync对此进行了字符串处理,这使我们只知道属性数据。

成功时,saveChanged触发关闭事件的集合进行一次处理。使用了一些代码,它可以为每个批次模型中已更改的每个属性触发特定事件一次。

Backbone.Collection.prototype.saveChanged = function() { 
    var me = this, 
     changed = me.getChanged(), 
     dummy = { 
      url: this.url, 
      toJSON: function() { 
       return changed.models; 
      } 
     }, 
     options = { 
      success: function (model, resp, xhr) { 
       for (var i = 0; i < changed.models.length; i++) { 
        changed.models[i].chnageSilently(); 
       } 
       for (var attr in changed.attributes) { 
        me.trigger("batchchange:" + attr); 
       } 
       me.trigger("batchsync", changed); 
      } 
     }; 
    return Backbone.sync("update", dummy, options); 
} 

然后,我们只需要对集合的getChanged()方法。这将返回一个对象2周的特性,改变后的模型的阵列以及哪些属性已改变的对象检举:

Backbone.Collection.prototype.getChanged = function() { 
    var models = [], 
     changedAttributes = {}; 
    for (var i = 0; i < this.models.length; i++) { 
     if (this.models[i].hasChanged()) { 
      _.extend(changedAttributes, this.models[i].changedAttributes()); 
      models.push(this.models[i]); 
     } 
    } 
    return models.length ? {models: models, attributes: changedAttributes} : null; 
} 

虽然这是预期的用途骨架“改变的模型”范式,整点的轻微滥用的配料是,当模型改变时,我们不希望发生任何事情(即任何事件发生)。

因此,我们必须将{silent:true}传递给模型的set()方法,所以使用backbone的hasChanged()来标记等待保存的模型是有意义的。当然,如果你为了其他目的而默默地改变模型,这会有问题 - collection.saveChanged()也会保存它们,所以值得考虑设置一个替代标志。在任何情况下,如果我们这样做,当保存时,我们需要确保骨干现在认为模型没有改变(不触发它们的改变事件),所以我们需要手动操纵模型,就好像它没有改变。该saveChanged()在我们改变模型方法进行迭代,并呼吁模式,这基本上是骨干model.change()方法不触发这个changeSilently()方法:

Backbone.Model.prototype.changeSilently = function() { 
    var options = {}, 
    changing = this._changing; 
    this._changing = true; 
    for (var attr in this._silent) this._pending[attr] = true; 
    this._silent = {}; 
    if (changing) return this; 

    while (!_.isEmpty(this._pending)) { 
     this._pending = {}; 
     for (var attr in this.changed) { 
     if (this._pending[attr] || this._silent[attr]) continue; 
     delete this.changed[attr]; 
     } 
     this._previousAttributes = _.clone(this.attributes); 
    } 
    this._changing = false; 
    return this; 
} 

用法:

model1.set({key: value}, {silent: true}); 
model2.set({key: value}, {silent: true}); 
model3.set({key: value}, {silent: true}); 
collection.saveChanged(); 

RE。 RESTfulness ..对集合的端点执行PUT以更改它的某些记录是不正确的。从技术上讲,PUT应该取代整个集合,但直到我的应用程序实际上需要替换整个集合时,我很乐意采取实用的方法。

1

你可以定义一个新的资源来完成这种行为,你可以称它为MyModelBatch

您需要实现在你的服务器端的新资源是能够消化的模型的Array和执行正确的动作:CREATEUPDATEDESTROY

你也需要实现一个Model在骨干网客户端与一个属性这是模式的阵列和专用url不利用id

关于重新渲染的事情,我建议你尝试有一个查看每个型号所以会有尽可能多的呈现作为模型已经改变,但他们会详细重新呈现不重复。

+0

谢谢。根据您使用临时模型的建议,我注意到Backbone.sync只查看模型的url属性和toJSON方法,因此不是使用实际的模型,我们可以很容易地伪造一个用于同步的模型。 toJSON只返回要被字符串化的模型属性的副本,所以我们可以使用它返回我们的模型数组。看到我的答案。 – hacklikecrack