Exclude model properties when syncing (Backbone.js

2019-01-16 06:10发布

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)

11条回答
我欲成王,谁敢阻挡
2楼-- · 2019-01-16 06:22

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, ...

查看更多
forever°为你锁心
3楼-- · 2019-01-16 06:25

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);
    }
});
查看更多
闹够了就滚
4楼-- · 2019-01-16 06:32

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);
},
查看更多
Fickle 薄情
5楼-- · 2019-01-16 06:36

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']
});
查看更多
\"骚年 ilove
6楼-- · 2019-01-16 06:38

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.

查看更多
淡お忘
7楼-- · 2019-01-16 06:39

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);
},
查看更多
登录 后发表回答