Backbone 中仅客户端的属性

Posted

技术标签:

【中文标题】Backbone 中仅客户端的属性【英文标题】:Client-side only attributes in Backbone 【发布时间】:2012-08-10 01:52:39 【问题描述】:

我有一个相当通用的模型和该模型的集合(见下文),我正在处理作为一系列视图的基础。在几个视图中,选择其中一个模型会生成操作(通过“选定”属性),我需要能够仅在客户端跟踪选择。

但是,在 Backbone 中似乎没有干净的方法可以做到这一点。客户端模型上添加/更改的任何属性都将同步到服务器。我不能在更改该属性时使用silent : yes,因为当change 事件在该属性上触发时,我需要触发我的视图更改。我想出的唯一方法是覆盖Backbone.Model上的save函数

我的问题:有没有办法让我缺少的只有客户端的属性,或者我的方法在结构上存在一些我没有看到的其他方面的缺陷?

    var CSEvent = Backbone.Model.extend(
        idAttribute: "_id",
        urlRoot : '/api/events',
        defaults: 
            title : "",
            type : "Native",
            repeatOrOneTime : "OneTime",
            selected : false
        
    );    

    var CSEventCollection = Backbone.Collection.extend(
        model: CSEvent,
        url: '/api/events',
        getSelectedEvent : function() 
            return this.find(function(csevent)  return csevent.get('selected') === true; );
        ,
        selectEvent : function(eventId) 
            this.deselectEvent();
            this.get(eventId).set(selected : true);
        ,
        deselectEvent : function() 
            this.getSelectedEvent().set(selected : false);
        
    );

【问题讨论】:

【参考方案1】:

尝试重写Model.toJSON() 方法,正如您在Backbone Model code 中看到的那样,该方法不是很复杂。官方文档也建议在特殊需要的情况下覆盖它。

试试这样的:

var CSEvent = Backbone.Model.extend(
  toJSON: function()
    return _.clone( _.pick( this.attributes, "title", "type", "repeatOrOneTime" ) );
  
);

【讨论】:

而且他可能不得不使用toJSON 以外的其他方式向视图发送数据(正如我们之前讨论过的:***.com/a/10779124/479863 和***.com/a/9687672/479863)。我一直想发送一个补丁来区分toJSON 的这两种用途。 @muistooshort ,确实(再次),我尽量避免使用override Backbone 方法,因为 collat​​eral 损害。单独使用的单独方法可能是一个好主意,但我猜 Backbone 支持者的回答是:“您可以轻松定义自己的 toTemplateJSON() 方法,Backbone 实现专注于简单性,并不是要解决所有问题个人目的” :) @fguillen - 无需调用 _.clone,因为 _.pick 会创建您提供给它的对象的副本,在本例中为“this.attributes”。【参考方案2】:

我不建议覆盖 Model.toJSON(),因为您可能希望在代码的其他部分使用 JSON 表示,例如将 Backbone 模型传递给微模板时。

自定义保存哪些属性的更好方法是在模型对象中覆盖the sync method:

   sync: function(method, model, options) 
        if (method == 'update' || method == 'create') 
            var newModel = this.clone();
            newModel.unset('ignoredAttribute', silent: true);
            return Backbone.sync.call(newModel, method, newModel, options);
         else 
            return Backbone.sync.call(this, method, this, options);
        
    ,

此示例忽略名为ignoredAttribute 的属性。

在您的代码中,它将是这样的:

  var CSEvent = Backbone.Model.extend(
    idAttribute: "_id",
    urlRoot : '/api/events',
    defaults: 
        title : "",
        type : "Native",
        repeatOrOneTime : "OneTime",
        selected : false
    ,
    sync: function(method, model, options) 
        if (method == 'update' || method == 'create') 
            var newModel = this.clone();
            newModel.unset('selected', silent: true);
            return Backbone.sync.call(newModel, method, newModel, options);
         else 
            return Backbone.sync.call(this, method, this, options);
        
    
);   

另一个简单的选择是将selected 作为对象属性(而不是作为主干托管属性),您仍然可以使用trigger 触发更改事件。对我来说,这是解决您问题的最简单方法:

  var CSEvent = Backbone.Model.extend(
    idAttribute: "_id",
    urlRoot : '/api/events',
    selected : false,
    defaults: 
        title : "",
        type : "Native",
        repeatOrOneTime : "OneTime"
    ,
    select: function() 
         this.selected = true;
         this.trigger('selected'); // you can use another event name here, ie. change
    ,
    deselect: function() 
         this.selected = false;
         this.trigger('deselected');
    
);   

【讨论】:

【参考方案3】:

我想提出一种使用上述两个原则来实现此目的的方法,而不覆盖 toJSON()

此模式提供了许多好处 - 例如,在仅将必要的属性发送到服务器之前对所有属性进行客户端验证。

以下面的例子为例,我们为用户提供了一种更改密码的方法。

var UserModel = Backbone.Model.extend(

  defaults: 
    username: "",
    password: 
      old: "",
      new: "",
      confirm: ""
    
  ,

  validate: function(attrs) 
    if (attrs.password.new !== attrs.password.confirm) 
      return "Passwords must match";
    
  ,

  toRemoteJSON: function() 
    var payload = this.toJSON();
    delete payload.password.confirm;
    return payload;
  ,

  sync: function(method, model, options) 
    if (method == 'update' || method == 'create') 
      var newModel = this.clone();
      newModel.clear( silent: true );
      newModel.set(this.toRemoteJSON(),  silent: true );
      return Backbone.sync.call(newModel, method, newModel, options);
     else 
      return Backbone.sync.call(this, method, this, options);
    
  

);

当模型为saved 时,validate() 方法在sync() 方法之前被调用,因此它会检查两个新密码是否匹配。然后sync 方法委托给toRemoteJSON(),这会在发送到服务器之前删除确认密码字段。

toRemoteJSON() 函数只是在 Diego 的解决方案中抽象了 newModel.unset() 部分。但这现在意味着您可以在基础对象中定义覆盖的sync,而从该基础对象扩展的对象只需要定义toRemoteJSON()

【讨论】:

以上是关于Backbone 中仅客户端的属性的主要内容,如果未能解决你的问题,请参考以下文章

在服务器上排序Backbone Paginator结果而不是客户端

Backbone.js:更改属性列表的智能更新

与backbone.js的多对多关系事件

WCF 客户端的默认属性值

Backbone.js、mongodb 和获取相关对象——客户端还是服务器端?

Backbone.js 错误报告实践