3

With Backbone, I'm trying to update and save to the server just one attribute:

currentUser.save({hide_explorer_tutorial: 'true'});

but I don't want to send all the other attributes. Some of them are actually the output of methods on the server-side and so they are not actually true attributes with setter functions.

Currently I'm using unset(attribute_name) to remove all the attributes that I don't want to update on the server. Problem is those attributes are then no longer available for local use.

Suggestions on how to only save certain attributes to the server?

Nikhil Agrawal
  • 26,128
  • 21
  • 90
  • 126
Drew Dara-Abrams
  • 8,016
  • 11
  • 40
  • 48

5 Answers5

20

As of Backbone 0.9.9

Just pass {patch:true} to the save function, like this:

currentUser.save({hide_explorer_tutorial: 'true'}, {patch:true});

From the documentation,

If instead, you'd only like the changed attributes to be sent to the server, call model.save(attrs, {patch: true}). You'll get an HTTP PATCH request to the server with just the passed-in attributes.

Drew Dara-Abrams
  • 8,016
  • 11
  • 40
  • 48
viky
  • 542
  • 1
  • 7
  • 19
  • Here's how I've accomplished this in the past: ```` save: function(attrs, options) { var whitelist = ["safe", "keys", "here"]; attrs = _.pick(attrs || this.toJSON(), whitelist); options = _.extend(options || {}, {patch: true}); return Backbone.Model.prototype.save.call(this, attrs, options); } ```` – Kabir Sarin Jul 17 '14 at 13:00
7

You can use toJSON on the model to do so.

toJSON : function(){
  return {hide_explorer_tutorial: this.get("hide_explorer_tutorial")};
}

This will be the only attribute sent to the backend on save.

Julien
  • 9,216
  • 4
  • 37
  • 38
  • 1
    Great, thanks! Will cause some problems with templates, but I guess it's just a choice of where to put the kludge. – Drew Dara-Abrams Mar 16 '11 at 05:11
  • 1
    @julien: you're overwrite in every case with this solution. How would handle the scenario where you want to submit only dirty attributes? – Alpha Jan 31 '12 at 01:34
  • Check my answer here regarding that http://stackoverflow.com/questions/5273369/backbone-js-partial-model-update/5274672#5274672 – Julien Jan 31 '12 at 19:38
4

In fact there is a much simpler way of achieving this

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) } ) ; 

For your particular case

var data = { id : currentUser.id ,  hide_explorer_tutorial: 'true' }  ;  
currentUser.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, ...

Thanks for voting

Pascal
  • 2,377
  • 3
  • 25
  • 40
  • 1
    Really simpler way, in addition I'd include `contentType: 'application/json'` to options hash, because, when passing `data` this way, it defaults to `application/x-www-form-urlencoded`. – wik Nov 18 '14 at 11:42
  • This is a great approach! Thanks a lot. This also works for model create actions (POST), which is where I was having trouble with the accepted answer. – RSmithlal Sep 06 '18 at 20:41
1

I guess this isn't currently possible: Backbone.js partial model update

Community
  • 1
  • 1
Drew Dara-Abrams
  • 8,016
  • 11
  • 40
  • 48
  • 1
    Correction: possible, but not without some efforts. – Julien Mar 15 '11 at 14:08
  • Client only attributes are even easier than delta model update like the linked discussion. You override toJSON and send only backend fields. No need to look at dirty fields in that case. I do it quite a lot. – Julien Mar 15 '11 at 14:09
0

There is a trick, if you do not set data property but attrs property on the options argument, the request payload would be the attrs property value instead of all the model attributes.

Note: This also works for model create actions (POST).

For your particular case:

var data = { hide_explorer_tutorial: 'true' };  
currentUser.save(data, { attrs : data });

You can find more details from the backbone.js 1.33 source code (line 1405 - 1409):

// 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));
}
Jinke Song
  • 26
  • 4