【问题标题】:Exclude model properties when syncing (Backbone.js)同步时排除模型属性 (Backbone.js)
【发布时间】:2012-10-24 15:04:01
【问题描述】:

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

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

有干净的方法吗?

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

【问题讨论】:

标签: javascript backbone.js underscore.js


【解决方案1】:

这似乎是最好的解决方案(基于@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);
    }
});

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

【讨论】:

  • attrs 可能为空,因此 JSON.stringify(attrs || this.attributes) 或 JSON.stringify(_.pick(attrs || this.attributes, "f1", "f2 ", ...)) 用于白名单
  • 很确定这个例子不太正确。您正在对 attrs 进行字符串化,然后尝试从中删除变量,就像它是一个对象一样......但它是一个字符串。
  • 已更新 - 虽然我不确定在哪种情况下 attrs 会被传递为空。
  • 我认为这个解决方案会导致奇怪的错误。如果您为 attrs 传入 null ,那么它将使用模型的属性并删除一对(attrs.selected 和 attrs.dontSync),因此每次调用 save 时都会丢失模型的属性。除非我读错了?
  • @EvanHobbs 看起来正确,我们应该克隆对象。
【解决方案2】:

在 Underscore 1.3.3 中,他们添加了 pick,在 1.4.0 中,他们添加了 omit,可以非常简单地使用它来覆盖模型的 toJSON 函数,以使用 _.pick 将属性列入白名单或使用 @987654325 将属性列入黑名单@。

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

Backbone.Model.extend({
    blacklist: ['selected',],
    toJSON: function(options) {
        return _.omit(this.attributes, this.blacklist);
    },
});

【讨论】:

  • _.pick_.omit 很棒,我使用它们,但在 save,而不是 toJSONtoJSON 方法的问题在于它会过滤掉视图所需的数据,而不仅仅是保存到服务器。
  • 没错,但我还要说,对我来说,我已经不使用 toJSON 进行视图/模板渲染,因为它对未定义的变量不是很宽容,所以我将整个模型传递给模板,然后我可以使用 model.has("field") 以防它尚未设置。 (例如新创建字段上的 ID)
  • "not forgiving" - 我的模板没有这个问题,toJSON 返回了我需要的所有内容:我所做的只是设置字段默认值:{ id: null },瞧,id 是设置:)
  • 这很好,但是,我有一个问题,即非同步属性在集合提取时被覆盖。可以保存吗?
  • 是的,您可以覆盖模型的 parse 函数并去除您没有覆盖的属性(使用 _.omit!),但这会导致它最初没有设置。但你可以围绕它编写代码。
【解决方案3】:

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

定义

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

【讨论】:

  • 是的,白名单感觉更好。如果我需要在不同情况下保存不同的东西,我会将它作为一个选项传递。
  • 顺便说一句 attrs 参数呢?它应该包含在 toJson
  • 嘿@msanjay 抱歉耽搁了,但是“包含在 toJson 中”是什么意思?
  • Oops by toJson 我的意思是 stringify,我现在不记得为什么了,但由于某种原因,我得到了它的使用:options.data = JSON.stringify(_.extend(whitelisted, attrs) );
  • 基本上,只要您的对象中有 attrWhiteList,您就不需要 _.extend 列入白名单。为什么?因为 _.pick 将为您提供正确的属性。如果要使用传递的 attr,可以使用 _.pick(attrs,this.attrWhiteList) 而不是 this.attributes
【解决方案4】:

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

如果你查看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 的主干一起使用,例如 fetch、save、delete ......

【讨论】:

  • 这很适合个案需要。不过滤掉每次显示的相关属性。但它是一个有效的解决方案,而且比这里提出的“逐案”解决方案更容易。
【解决方案5】:

根据几个答案,这说明了空对象的情况和如果 options.data 已设置,则不发送 contentType 的 Backbone 中的条件:

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

【讨论】:

    【解决方案6】:

    我发现接受的解决方案存在一些问题,因为 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);
        }
    });
    

    【讨论】:

    • 我认为现在这是正确的解决方案——它不需要对Backbone.syncModel.save 进行修改或复杂假设,它允许您通过 XHR 传递您想要的任何属性,而无需踩在Model.save() 所做的许多令人困惑的事情中。
    • 这如宣传的那样有效,我同意看起来比当前接受的答案更简单。
    【解决方案7】:

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

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

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

    【讨论】:

    • toJSON 方法的问题在于它会过滤掉视图所需的数据,而不仅仅是保存到服务器
    • 请注意,您可以将选项传递给toJSON,以便在需要查看时绕过您的修改。
    【解决方案8】:

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

    var model = new Backbone.Model();
    model.save(null, {
      wait: true,
      success: function() {
      },
      attrs: _.omit(model.attributes, 'selected')
    });
    

    【讨论】:

    • 如果您需要自定义每个操作属性,这是一个很好的解决方案。但如果您想在保存时始终忽略某些属性,它将无法扩展。
    • @SimonBoudrias 如果是这样,你可以考虑这个解决方案:gist.github.com/bammoo/d8b09252e4cfa081d0e6
    【解决方案9】:

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

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

    【讨论】:

      【解决方案10】:

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

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

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

      【讨论】:

        【解决方案11】:

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

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

        var myModel = new Backbone.ModelSave.extend({
            notSync: ['name', 'age']
        });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-11
          • 2017-02-21
          • 1970-01-01
          • 2014-06-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多