What is the right way to perform PATCH
request while saving model\'s attributes in Backbone.js?
As of Backbone.js v0.9.9, you can simply pass { patch: true }
to save()
.
Read more: http://backbonejs.org/#changelog
In addition to James Cropchos answer I want add the following, because this stole some hours from me and maybe helps someone else:
If you use model.save(attributesToPatchObject,{patch: true})
like it is possible since backbone v.0.9.9 as stated in James Cropchos answer, you may wonder how to determine which attributes have changed since the last call of model.save()
to pass them in as attributesToPatchObject
which is the first argument from model.save()
(or model.fetch()
if you didn't save the model lately).
Backbone itself didn't keep track of those attributes. I thought the method model.changedAttributes()
could fit, but as the backbone-doc says this method returns
a hash of only the model's attributes that have changed since the last set, or false if there are none
So this method didn't fit for this need. After some research I found out that backbone itself didn't keep track of unsaved attributes (I know, not a brilliant finding if I had read the docs more carefully).
I found out that backbone.trackit is a backbone plugin which exactly add the needed feature to backbone, by adding the method unsavedAttributes()
to the model. The docs of backbone.trackit says about this method:
Symmetric to Backbone's model.changedAttributes(), except that this returns a hash of the model's attributes that have changed since the last save, or false if there are none. Like changedAttributes, an external attributes hash can be passed in, returning the attributes in that hash which differ from the model.
It works like this:
//fetch an existing model from server
model.fetch({
success : function(model, respose, options) {
//tell backbone.trackit to track unsaved Attributes
model.startTracking();
}
});
//now some changes to the model happen
model.set("someProperty", "someValue");
/* save the model to server using the PATCH-Method
and only send the unsaved Attributes;
in this case only "someProperty" is sent
*/
model.save(model.unsavedAttributes(), {patch: true});
Since the unsavedAttributes()
returns false if there are no unsaved Attributes, you could additionally wrap your save()
statement within an if-condition which checks if unsavedAttributes()
returns something other then false and only do your PATCH-Request if it's needed (because something changed).
NOTE: You didn't have to call fetch()
to use startTracking()
so you can use this method even with newly created models (model.isNew()
returns true on that model), if there is a usecase for that.
Hopes this may save someone a little bit of research time.
You'll have to override Backbone.sync
and extend the existing method mapper
var methodMap = {
'create': 'POST',
'update': 'PUT',
'delete': 'DELETE',
'read': 'GET',
'patch': 'PATCH'
};
you'll have to create your own patch method on a model like
Backbone.Model.prototype.patch = function(options)
{
// some code here that checks what attributes have changed since last save
var xhr = (this.sync || Backbone.sync).call(this, 'patch', this, options);
return xhr;
}
I'm sure you can extend Backbone further to include OPTIONS
and HEAD
if you needed to
Note though, that even through jQuery supports the PATCH, OPTIONS and HEAD methods, your end-users' browser may not.