可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Is there a way to exclude certain property from my model when I sync?
For example, I keep in my model information about some view state. Let's say I have a picker module and this module just toggle a selected
attributes on my model. Later, when I call .save()
on my collection, I'd want to ignore the value of selected
and exclude it from the sync to the server.
Is there a clean way of doing so?
(Let me know if you'd like more details)
回答1:
This seems like the best solution (based on @nikoshr referenced question)
Backbone.Model.extend({
// Overwrite save function
save: function(attrs, options) {
options || (options = {});
attrs || (attrs = _.clone(this.attributes));
// Filter the data to send to the server
delete attrs.selected;
delete attrs.dontSync;
options.data = JSON.stringify(attrs);
// Proxy the call to the original save function
return Backbone.Model.prototype.save.call(this, attrs, options);
}
});
So we overwrite save function on the model instance, but we just filter out the data we don't need, and then we proxy that to the parent prototype function.
回答2:
In Underscore 1.3.3 they added pick and in 1.4.0 they added omit which can be used very simply to override your model's toJSON
function to whitelist attributes with _.pick
or blacklist attributes with _.omit
.
And since toJSON
is used by the sync command for passing the data to the server I think this is a good solution as long as you do not want these fields wherever else you use toJSON
.
Backbone.Model.extend({
blacklist: ['selected',],
toJSON: function(options) {
return _.omit(this.attributes, this.blacklist);
},
});
回答3:
my solution combine all the above. just use white list instead of black one .. this is good rule in general
define
attrWhiteList:['id','biography','status'],
and then overwrite the save
save: function(attrs, options) {
options || (options = {});
//here is whitelist or all
if (this.attrWhiteList != null )
// Filter the data to send to the server
whitelisted = _.pick(this.attributes, this.attrWhiteList);
else
whitelisted =this.attributes;
/* it seems that if you override save you lose some headers and the ajax call changes*/
// get data
options.data = JSON.stringify(whitelisted);
if ((this.get('id') == 0) || (this.get('id') == null))
options.type = "POST"
else
options.type = "PUT";
options.contentType = "application/json";
// options.headers = {
// 'Accept': 'application/json',
// 'Content-Type': 'application/json'
// },
// Proxy the call to the original save function
return Backbone.Model.prototype.save.call(this, attrs, options);
},
回答4:
In fact there is a much simpler way of achieving this without messing with backbone save or sync function since you would no be expecting this behaviour to be permanent
if you look at backbone.js line 1145 you will see that
// 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));
}
Which means that you may override the data part of the xhr by putting data in your options
Since backbone save requires model.save([attributes], [options])
But remember that attributes like id might be essential to proper saving
Example
model.save( {}, { data: JSON.stringify(data) } ) ;
So you should be doing something like this
var data = { id : model.id , otherAttributes : 'value' } ;
model.save( {}, { data : JSON.stringify(data) } );
This do the trick quite well for me and could be used with any backbone with xhr such as fetch, save, delete, ...
回答5:
Based on several of the answers, this accounts for cases of null objects and a conditional in Backbone that doesn't sent the contentType
if options.data
is already set:
EDITABLE_ATTRIBUTES = ["name", "birthdate", "favoriteFood"];
...
save: function(attrs, options) {
// `options` is an optional argument but is always needed here
options || (options = {});
var allAttrs = _.extend({}, this.attributes, attrs);
var allowedAttrs = _.pick(allAttrs, EDITABLE_ATTRIBUTES);
// If `options.data` is set, Backbone does not attempt to infer the content
// type and leaves it null. Set it explicitly as `application/json`.
options.contentType = "application/json";
options.data = JSON.stringify(allowedAttrs);
return Backbone.Model.prototype.save.call(
this, allowedAttrs, options);
},
回答6:
Since save
uses toJSON
we override it:
toJSON: function(options) {
var attr = _.clone(this.attributes);
delete attr.selected;
return attr;
},
But it may not work if you're using toJSON and need selected
in views for example. Otherwise you probably need to override save
method.
回答7:
Set options.attrs will allow you customise api param:
var model = new Backbone.Model();
model.save(null, {
wait: true,
success: function() {
},
attrs: _.omit(model.attributes, 'selected')
});
回答8:
I found some problems with the accepted solution, as options.data modifies the way Backbone makes the calls. Better using options.attrs as this:
Backbone.Model.extend({
save: function (attrs, options) {
options = options || {};
attrs = _.extend({}, _.clone(this.attributes), attrs);
// Filter the data to send to the server
delete attrs.selected;
options.attrs = attrs;
// Proxy the call to the original save function
return Backbone.Model.prototype.save.call(this, attrs, options);
}
});
回答9:
If it is a one-off occasion, you could use mode.unset('selected', { silent:true })
(silent is set only to avoid firing the change event), to remove the attribute... This has the not so nice counter-effect of having to re-set it after saving though.
This said, I totally endorse one of the solutions above. Moreover if this is something you need on a more regular basis.
回答10:
To set only desired values, use HTTP PATCH insead of HTTP POST. On the backbone side, just add a patch attribute to the save method:
entity.save(data,{patch:true})
Using save with this attribute, only fields passed as data
are sent to the server.
回答11:
Having this same issue, I decided to create a small module that can help : https://github.com/lupugabriel1/backbone-model-save
This is how you can use it in your models:
var myModel = new Backbone.ModelSave.extend({
notSync: ['name', 'age']
});