Backbone.js部分模型更新
保存更改时是否可以只发送模型的修改属性?
顺便说一句,有没有任何“官方”Backbone.js组/邮件列表来问这样的问题?
目前骨干网不支持将模型的一部分发送到服务器。 这将是一个有趣的补充,但。
如果浏览源代码 ,可以看到Backbone.sync
(负责与数据存储进行通信的骨干部分)是骨干网中最简单的组件之一,只是将jQuery支持包装在jQuery或Zepto中。
UPDATE
起始骨干版本0.9.10,部分模型更新通过本地支持
model.save(attrs, {patch: true})
骨干不支持这个开箱即用,但你有所有的工具来实现这一点。 如果您查看Backbone.sync,您会看到它在您的模型上调用JSON来获取实际的数据发送。 现在你可能不得不调整这一点,但这是它的要点:
initialize: function(){ this.dirtyAttributes = {} }, set: function(attrs, options){ Backbone.Model.prototype.set.call(this, attrs, options); _.extend(this.dirtyAttributes, attrs); }, toJSON : function(){ json = this.dirtyAttributes; this.dirtyAttributes = {}; return json; }
如果你想要一个完整的解决scheme,你需要应用相同的逻辑来解除,清除,保存等,但我想你会得到如何做到这一点。 我把重新设置的toJSON函数的脏属性,但它应该真正在成功callback(当调用保存时)。
更新:开始骨干版本0.9.10,部分更新通过本地支持
model.save(attrs, {patch: true})
直到0.9.9没有直接编辑backbone.js库文件的方法。 只需将以下代码添加到应用程序js文件中,并在加载backbone.js之后加载它。
//override the Backbone.sync to send only the changed fields for update (PUT) request var Original_BackboneSync = Backbone.sync; Backbone.sync = function(method, model, options) { /* just handle the data picking logic for update method */ if (!options.data && model && method == 'update') { options.contentType = 'application/json'; options.data = JSON.stringify(model.changedAttributes() || {}); } //invoke the original backbone sync method return Original_BackboneSync.apply(this, arguments); }; //Tested in Backbone.js 0.9.1
我尝试了几个在这里提出的技术,但最终决定直接修改Backbone.Model和Backbone.sync。 我想提供的是提供这种function的微创方法,并不需要指导我的团队中的开发人员使用重要的主干方法; 太容易出错。 我的解决scheme只涉及将选项传递给模型的“保存”方法。 例如:
//Note that this could be from your view or anywhere you're invoking model.save saveToModel : function() { this.model.save({ field1 : field1Value, field2 : field2Value, field3 : field3Value }, {partialUpdate : true} }
现在,为了启用这个function,我对Backbone.Model.save和Backbone.sync做了一些很小的修改。 这是对Backbone.Model.save的改变:
//If a partialUpdate is required, create a member on the options //hash called updateAttrs and set it to attrs if (options.partialUpdate != "undefined" && options.partialUpdate) { options.updateAttrs = attrs; } //--->>>Put the block above right above the return line return (this.sync || Backbone.sync).call(this, method, this, options);
这里发生的是,如果partialUpdate作为选项被传递,那么在选项散列上会创build一个名为updateAttrs的新成员。 选项散列自动传递给Backbone.sync。
对于Backbone.sync,我更改了以下条件:
// Ensure that we have the appropriate request data. if (!params.data && model && (method == 'create' || method == 'update')) { params.contentType = 'application/json'; params.data = JSON.stringify(model.toJSON()); }
至…
// Ensure that we have the appropriate request data. if (!params.data && model && (method == 'create' || method == 'update')) { params.contentType = 'application/json'; //If doing a partial model update, then grab the updateAttrs member //from options. Will not interfere with line directly below as params.data //will have been set. params.data = (options.partialUpdate != "undefined" && options.partialUpdate) ? params.data = JSON.stringify(options.updateAttrs) : params.data = JSON.stringify(model.toJSON()); }
添加额外的条件检查以查看partialUpdate是否已设置,如果是,则将params.data设置为options.updateAttrs。 这将被传递给jQuery的Ajax方法。
而不是覆盖Backbone.sync
你可以在Model.sync
方法内Model.sync
。 既然你不能在那里访问model.changedAttributes()
,一定要在这个方法里面返回false。
sync: (method, model, options) -> if method is "update" options.contentType = 'application/json' changedData = {} for attr in _.keys(options.changes) changedData[attr] = model.get(attr) options.data = JSON.stringify changedData Backbone.sync method, model, options
如果你需要发送更新请求到一个只有特定属性的服务器,你可以做类似的事情:
saveAttributes: (attributes, options={}) -> data = {} _(attributes).each (attribute) => data[attribute] = @get(attribute) params = data: $.param(data) _.extend(params, options) Backbone.sync('update', null, params)
更多信息: https : //github.com/documentcloud/backbone/pull/573
你可以用_.extend Backbone.Model.prototype
扩展它
这里的大多数答案是直接或间接修改sync
function。 这是我的小技巧来克服这一点:
当你调用你的model.save
,实际上可以传入第二个参数,当Backbone尝试调用同步时,它将与$.ajax
一起传递。 我做了这样的部分更新,更多的显式指定要提交的字段:
/** * On user clicking on "mark important" */ onMarkImportantBtnClick: function() { var marked = this.model.get('UserFeed.marked_important'), data = { UserFeed: { marked_important: !marked } }; this.model.save(data, {data: JSON.stringify(data), contentType: 'application/json'}); }
这个动作正确地更新了我的模型属性,并且只把JSON.stringify
中提到的数据发送给服务器。 contentType
在这里是必需的,更好
这是因为Backbone.sync
有这些行 ,我们通过传递data
属性否定它:
if (!options.data && model && (method == 'create' || method == 'update')) { params.contentType = 'application/json'; params.data = JSON.stringify(model.toJSON()); }
请访问此页面: https : //plus.google.com/103858073822961240171/posts/1gTcu6avmWQ
注意:这个模型inheritance自powmedia的DeepModel以支持嵌套的模型属性
编辑
自骨干0.9.9以来, patch
选项已被添加,所以这个技巧只适用于以前的版本。
要仅将脏数据提交回服务器,请在save
提供{patch: true}
,例如
this.model.save(modifiedData, {patch: true});
感谢@林肯B指出。
使用Jayyy V的(非常好的)答案,我重新编写了一点,使同步function成为一个白名单,所以你可以给它一个键保存的数组。
var Original_BackboneSync = Backbone.sync; Backbone.sync = function(method, model, options) { /* check if a whitelist was in options */ if (options.whitelist) { options.contentType = 'application/json'; /* use underscore method for picking only whitelisted attributes to save */ options.data = JSON.stringify(_.pick(model.attributes, options.whitelist)); } //invoke the original backbone sync method return Original_BackboneSync.apply(this, arguments); };
build立在@ Julien的文章:你可以添加到你的模型,它只会发送你传入的属性,而不是整个模型。 您仍然可以使用save作为默认行为,并且您可以使用partialSave来发送那些作为参数传入的属性。 我已经testing了这个,它对我有用。
partialSave: function(attr, options) { //use this method instead of save() this.dirtyAttributes = attr; this.save(attr, options); }, toJSON: function() { //overrides Backbone.Model.prototype.toJSON if (this.dirtyAttributes) { var attr = this.dirtyAttributes; this.dirtyAttributes = null; return attr; } return Backbone.Model.prototype.toJSON.apply(this, arguments); },
事实上,有一个更简单的方法来实现这一点
如果你看看backbone.js行1145你会看到
// Ensure that we have the appropriate request data. if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) { params.contentType = 'application/json'; params.data = JSON.stringify(options.attrs || model.toJSON(options)); }
这意味着你可以通过将数据放在你的选项中来覆盖xhr的数据部分
由于骨干保存需要model.save([attributes], [options])
但请记住,像ID这样的属性可能是正确保存的关键
例
model.save( {}, { data: JSON.stringify(data) } ) ;
所以你应该做这样的事情
var data = { id : model.id , otherAttributes : 'value' } ;
要么
var data = model.toJSON () ; remove data.tempData ;
最后
model.save( {}, { data : JSON.stringify(data) } );
这个技巧对我来说很好,可以和任何支持xhr的骨干一起使用,例如抓取,保存,删除,…
乱七八糟的保存,同步或toJSON看起来错了
我创build了扩展模型。
var CModel = Backbone.Model.extend({ save: function(attributes, options) { if(_.isUndefined(options)) { options = {}; } var isNeedAttrsRefresh = false, basicAttributes = null; if(!_.isUndefined(options.fields)) { basicAttributes = _.clone(this.attributes); var newAttributes = {}; _.each(this.attributes, function(value, name) { if(options.fields.indexOf(name) > -1) { newAttributes[name] = value; } }); this.attributes = newAttributes; isNeedAttrsRefresh = true; } this.isSaving = true; var result = Backbone.Model.prototype.save.apply(this, arguments); this.isSaving = false; if(isNeedAttrsRefresh) { this.attributes = basicAttributes; } return result; } });
使用示例:
var CommentModel = CModel.extend({ ... }
并允许字段保存:
comment.save(null, { fields: ['message', 'entry_id', 'module_id', 'parent_id'] });