43

同步时有没有办法从我的模型中排除某些属性?

例如,我在模型中保留有关某些视图状态的信息。假设我有一个选择器模块,这个模块只是selected在我的模型上切换一个属性。稍后,当我调用.save()我的集合时,我想忽略 的值selected并将其从同步到服务器中排除。

有没有一种干净的方法呢?

如果您想了解更多详情,请告诉我

4

11 回答 11

47

这似乎是最好的解决方案(基于@nikoshr 引用的问题)

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

所以我们在模型实例上覆盖保存函数,但我们只是过滤掉我们不需要的数据,然后我们将其代理给父原型函数。

于 2012-10-24T17:47:21.013 回答
35

在 Underscore 1.3.3 中,他们添加了pick,在 1.4.0 中,他们添加了omit,它可以非常简单地用于覆盖模型的toJSON功能,以将属性列入白名单_.pick或将属性列入黑名单_.omit

由于toJSON同步命令用于将数据传递到服务器,因此我认为这是一个很好的解决方案,只要您不希望在其他任何地方使用这些字段toJSON

Backbone.Model.extend({
    blacklist: ['selected',],
    toJSON: function(options) {
        return _.omit(this.attributes, this.blacklist);
    },
});
于 2013-03-20T15:43:13.163 回答
11

我的解决方案结合了以上所有内容。只需使用白名单而不是黑名单.. 一般而言,这是一个很好的规则

定义

          attrWhiteList:['id','biography','status'],

然后覆盖保存

  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);
},
于 2013-07-19T17:01:03.803 回答
6

事实上,有一种更简单的方法可以实现这一点,而不会弄乱主干保存或同步功能,因为您不会期望这种行为是永久性的

如果您查看backbone.js 第1145 行,您会看到

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

这意味着您可以通过将数据放入选项中来覆盖 xhr 的数据部分

由于主干保存需要 model.save([attributes], [options])

但请记住,像 id 这样的属性对于正确保存可能是必不可少的

例子

model.save( {}, { data: JSON.stringify(data) } ) ; 

所以你应该做这样的事情

var data = { id : model.id , otherAttributes : 'value' }  ;  
model.save( {}, { data : JSON.stringify(data) } );

这对我来说做得很好,可以与任何带有 xhr 的主干一起使用,例如获取、保存、删除......

于 2014-08-04T11:04:51.000 回答
3

基于几个答案,这说明了空对象的情况和 Backbone 中未发送contentTypeifoptions.data的条件已设置:

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);
},
于 2014-03-26T23:25:49.397 回答
3

我发现接受的解决方案存在一些问题,因为 options.data 修改了 Backbone 进行调用的方式。更好地使用 options.attrs :

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);
    }
});
于 2015-02-10T16:05:32.240 回答
2

由于save使用toJSON我们覆盖它:

    toJSON: function(options) {
        var attr = _.clone(this.attributes);
        delete attr.selected;
        return attr;
    },

selected但是如果你使用 toJSON 并且需要在视图中,它可能不起作用。否则你可能需要重写save方法。

于 2012-10-24T15:25:54.650 回答
2

设置 options.attrs 将允许您自定义 api 参数:

var model = new Backbone.Model();
model.save(null, {
  wait: true,
  success: function() {
  },
  attrs: _.omit(model.attributes, 'selected')
});
于 2014-07-10T07:03:13.933 回答
0

如果这是一次性的场合,您可以使用mode.unset('selected', { silent:true })(设置静音只是为了避免触发更改事件)来删除属性......这有一个不太好的反效果,必须在保存后重新设置它尽管。

这就是说,我完全赞同上述解决方案之一。此外,如果这是您更经常需要的东西。

于 2012-10-27T16:35:24.267 回答
0

要仅设置所需的值,请使用 HTTP PATCH 而不是 HTTP POST。在主干端,只需在 save 方法中添加一个补丁属性:

entity.save(data,{patch:true})

使用带有此属性的保存,只有作为传递的字段data被发送到服务器。

于 2014-08-18T13:09:52.147 回答
0

遇到同样的问题,我决定创建一个可以提供帮助的小模块:https ://github.com/lupugabriel1/backbone-model-save

这是您可以在模型中使用它的方式:

var myModel = new Backbone.ModelSave.extend({
    notSync: ['name', 'age']
});
于 2014-09-25T17:46:16.323 回答