保存更改时是否可以仅发送模型的修改属性?
顺便说一句,是否有任何“官方”Backbone.js小组/邮件列表可以提出这类问题?答案 0 :(得分:46)
Backbone不支持开箱即用,但您拥有实现这一目标的所有工具。 如果您查看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;
}
如果你想要一个完整的解决方案,你需要应用相同的逻辑来取消设置,清除,保存等。但我想你会得到如何做到这一点。我把脏属性的重置放在toJSON函数中,但它应该在成功回调中(当调用save时)。
答案 1 :(得分:33)
目前,骨干网不支持将部分模型发送到服务器。这将是一个有趣的补充。
如果您browse the source,您可以看到Backbone.sync
(负责与数据存储通信的主干部分)是骨干网中最简单的组件之一,只需在jQuery中包含ajax支持或者Zepto。
的更新强>
启动主干版本0.9.10,本地支持部分模型更新
model.save(attrs, {patch: true})
答案 2 :(得分:6)
更新:启动主干版本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
答案 3 :(得分:2)
我尝试了这里建议的几种技术,但最后决定直接修改Backbone.Model和Backbone.sync。我想提供的是一种提供此功能的微创方法,不需要指示我的团队中的开发人员覆盖骨干方法;太容易出错了。我的解决方案只涉及将选项传递给模型的“保存”方法。例如:
//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}
}
现在,为了启用此功能,我对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作为选项传递,则会在选项哈希上创建名为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方法。
答案 4 :(得分:2)
您可以在Backbone.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
答案 5 :(得分:1)
如果您需要向仅具有特定属性的服务器发送更新请求,您可以执行类似的操作:
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
答案 6 :(得分:1)
这里的大部分答案都是直接或间接修改sync
功能。这是我克服这个问题的小技巧:
当您呼叫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
has these lines,我们通过传递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
注意:此模型继承自powmedia的DeepModel以支持嵌套模型属性
的修改
自Backbone 0.9.9以来,添加了patch
选项,因此此技巧仅适用于以前的版本。
要仅将脏数据提交回您的服务器,请在{patch: true}
中提供save
,以便
this.model.save(modifiedData, {patch: true});
感谢@Lincoln B指出它。
答案 7 :(得分:0)
使用Jayyy V的(非常好的)答案,我重写了一点,使同步功能采用白名单,这样你就可以给它一组保存的密钥。
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);
};
答案 8 :(得分:0)
以@ Julien的帖子为基础: 您可以将其添加到模型中,它只会发送您传入的属性而不是整个模型。您仍然可以使用save作为默认行为,并且当您希望仅将作为参数传递的属性发送时,可以使用partialSave。我测试了这个,它对我有用。
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);
},
答案 9 :(得分:0)
实际上有一种更简单的方法来实现这个
如果你看看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的任何骨干一起使用,例如fetch,save,delete,...
与save,sync或toJSON混淆看起来错误
答案 10 :(得分:0)
我创建了扩展模型。
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'] });