Backbone中仅客户端属性

时间:2012-08-13 19:30:40

标签: backbone.js

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

然而,似乎在Backbone中没有干净的方法来做到这一点。在客户端上模型上添加/更改的任何属性都将同步到服务器。更改该属性时我无法使用{silent : yes},因为当change事件触发该属性时,我需要触发视图中的更改。我提出的唯一方法是覆盖save

上的Backbone.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});
        }
    });

3 个答案:

答案 0 :(得分:5)

尝试覆盖Model.toJSON()方法,正如您在Backbone Model code中看到的那样,这种方法并不复杂。官方文件还建议在有特殊需要的情况下覆盖它。

尝试这样的事情:

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

答案 1 :(得分:1)

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

自定义保存哪些属性的更好方法是覆盖Model对象中的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作为对象属性(而不是作为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');
    }
});   

答案 2 :(得分: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);
    }
  }

});

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

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