无论何时在模型上设置了一个特定的属性,并且它被保存,计算的负载将被消除,并且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应该替代整个集合,尽管直到我的应用程序实际上需要替换整个集合,我很高兴采取务实的方法.