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 方法,因为 collateral 损害。单独使用的单独方法可能是一个好主意,但我猜 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);
);
当模型为save
d 时,validate()
方法在sync()
方法之前被调用,因此它会检查两个新密码是否匹配。然后sync
方法委托给toRemoteJSON()
,这会在发送到服务器之前删除确认密码字段。
toRemoteJSON()
函数只是在 Diego 的解决方案中抽象了 newModel.unset()
部分。但这现在意味着您可以在基础对象中定义覆盖的sync
,而从该基础对象扩展的对象只需要定义toRemoteJSON()
。
【讨论】:
以上是关于Backbone 中仅客户端的属性的主要内容,如果未能解决你的问题,请参考以下文章
在服务器上排序Backbone Paginator结果而不是客户端