Skip to content Skip to sidebar Skip to footer

Backbone.js Partial Model Update

Is it possible to send just the modified properties of a model when saving the changes? BTW, Are there any 'official' Backbone.js group/mailing list to ask this kind of questions?

Solution 1:

Backbone does not support this out of the box, but you have all the tools to make that happen. If you look at Backbone.sync you will see that it calls toJSON on your model to get the actual data to send. Now you might have to tweak this out, but here is the gist of it:

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

If you want a complete solution you need to apply the same logic to unset, clear, save, etc. But I guess you get how to do this. I put the reset of the dirty attributes in the toJSON function, but it should really be in the success callback (when calling save).

Solution 2:

Currently backbone does not support sending part of the model to the server. It would be an interesting addition though.

If you browse the source you can see that Backbone.sync (the part of backbone that is responsible for communicating with the data store) is one of the simplest components in backbone and simply wraps the ajax support in jQuery or Zepto.

UPDATE

starting backbone version 0.9.10, partial model update is supported natively via

model.save(attrs, {patch:true})

Solution 3:

UPDATE: starting backbone version 0.9.10, partial update is supported natively via

model.save(attrs, {patch:true})

Until 0.9.9 An approach without directly editing the backbone.js library file. Just the add the following code in application js file and load it after backbone.js gets loaded.

//override the Backbone.sync to send only the changed fields for update (PUT) requestvarOriginal_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 methodreturnOriginal_BackboneSync.apply(this, arguments);
};

//Tested in Backbone.js 0.9.1

Solution 4:

I tried several of the techniques that were suggested here, but in the end, decided to modify Backbone.Model and Backbone.sync directly. What I wanted to provide was a minimally invasive method for providing this functionality that didn't require instructing developers on my team on overriding backbone methods; just too prone to error. My solution involves only passing an option to the model's "save" method. For example:

//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}
}

Now, to enable this functionality, I made some very minor modifications to Backbone.Model.save and Backbone.sync. Here's the change to Backbone.Model.save:

//If a partialUpdate is required, create a member on the options//hash called updateAttrs and set it to attrsif (options.partialUpdate != "undefined" && options.partialUpdate) {
    options.updateAttrs = attrs;
}
//--->>>Put the block above right above the return linereturn (this.sync || Backbone.sync).call(this, method, this, options);

What happens here is that if partialUpdate is passed as an option, then a new member called updateAttrs is created on the options hash. The options hash is automatically passed to Backbone.sync.

For Backbone.sync, I changed the following conditional:

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

to...

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

Adding the extra conditional checks to see if partialUpdate was set, then if it is, set params.data to options.updateAttrs. This will then be passed to the jquery Ajax method.

Solution 5:

Instead of overwriting Backbone.sync you could just do it inside the Model.sync method. Since you can't access model.changedAttributes() there, be sure to always return false inside this method.

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

Post a Comment for "Backbone.js Partial Model Update"