5

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

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

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

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

3 回答 3

5

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

尝试这样的事情:

var CSEvent = Backbone.Model.extend({
  toJSON: function(){
    return _.clone( _.pick( this.attributes, "title", "type", "repeatOrOneTime" ) );
  }
});
于 2012-08-13T19:53:01.890 回答
1

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

自定义保存哪些属性的更好方法是覆盖模型对象中的同步方法:

   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作为对象属性(而不是作为 Backbone 托管属性),您仍然可以使用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');
    }
});   
于 2012-08-14T03:51:43.947 回答
1

我想提出一种使用上述两个原则来实现这一目标的方法,而不会覆盖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()函数只是对newModel.unset()Diego 解决方案中的部分进行抽象。但这现在意味着您可以sync在基础对象中定义被覆盖的对象,而从该对象扩展的对象只需要定义toRemoteJSON().

于 2012-10-05T10:53:33.677 回答