无论何时在模型上设置了一个特定的属性,并且它被保存,计算的负载将被消除,并且UI重新上弹.
但是,我想要能够一次设置几个模型的属性,只有一旦设置完毕,才能进行保存和重新登录.当然,我不想为一个操作提供几个http请求,绝对不需要重新使用十次接口.
我希望在Backbone.Collection上找到一个保存方法,该方法可以计算出哪些模型hasChanged(),将它们一起作为json发送到后端.然后可以通过集合上的事件来触发重画.没有这样的运气.
这似乎是一个很常见的要求,所以我想知道为什么Backbone没有实现.这是否符合RESTful架构,可以将多项功能保存到单个端点?如果是这样,那么什么?让1000个请求持续1000个小项目是没有办法的.
所以,是唯一的解决方案来增加Backbone.Collection与我自己的保存方法,迭代所有的模型,并建立所有的更改的json,并发送到后端?或者有人有一个更整洁的解决方案(或者我只是错过了一些东西!)?
解决方法
saveChangeMethod创建一个要传递给Backbone.sync的虚拟模型.所有骨干的同步方法需要一个模型就是它的url属性和toJSON方法,所以我们可以很容易的敲出来.
在内部,模型的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()方法,所以使用骨干的hasChanged()来标记等待保存的模型是有意义的.当然,如果您为了其他目的而以静默方式更改模型,那么这将是一个问题. – collection.saveChanged()将保存这些,所以值得考虑设置一个替代标志.
无论如何,如果我们这样做,当保存时,我们需要确保骨干网现在认为模型没有改变(没有触发他们的改变事件),所以我们需要手动操作模型,就好像它没有被改变了saveChanged()方法迭代我们改变的模型,并在模型上调用这个changeSilently()方法,这基本上只是Backbone的没有触发器的model.change()方法:
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();
回覆. RESTfulness ..对集合的端点进行PUT更改其“某些”记录是不正确的.技术上,PUT应该替代整个集合,尽管直到我的应用程序实际上需要替换整个集合,我很高兴采取务实的方法.