【发布时间】:2014-05-11 19:59:20
【问题描述】:
我的骨干模型中需要虚拟属性,但骨干似乎不支持这一点,我将如何自己实现它。
虚拟属性是指仅在客户端维护的属性,不保存/同步到服务器。我想使用它们来存储仅与客户端视图渲染相关的状态信息,例如是否选择/检查模型。我将在视图的模板渲染中使用模型属性,但我不希望将这些值发送到服务器或保存在数据库中。
【问题讨论】:
我的骨干模型中需要虚拟属性,但骨干似乎不支持这一点,我将如何自己实现它。
虚拟属性是指仅在客户端维护的属性,不保存/同步到服务器。我想使用它们来存储仅与客户端视图渲染相关的状态信息,例如是否选择/检查模型。我将在视图的模板渲染中使用模型属性,但我不希望将这些值发送到服务器或保存在数据库中。
【问题讨论】:
如果您只想在客户端将属性存储在模型上,为什么不直接使用:
model.set({attribute: "client-side only"})
代替:
model.fetch()
为避免触发更改事件,您可以传入:
model.set({silent:true})
尽管文档不建议这样做。如果您感觉更冒险,您还可以覆盖 set 方法以使其真正保持沉默,如本答案中所述:
Truly change a model attribute silently in Backbone.js?
更新:
环顾四周: Backbone.js partial model update 和 Exclude model properties when syncing (Backbone.js)
看起来您拥有的最简单的选项是:
model.save(model.changedAttributes(), {patch: true});
或者如果您需要以一种良好的安静方式创建/更新这些对象,您可以像这样覆盖主干sync:
Backbone.Model.extend({
// Overwrite save function
save: function(attrs, options) {
options || (options = {});
// 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
Backbone.Model.prototype.save.call(this, attrs, options);
}
});
图片来源:Simon Boudrias
【讨论】:
几个选项:
您可以创建一个通用主干模型并使用它来存储和侦听视图状态的属性。
StatefulView = Backbone.View.extend({
initialize: function(options) {
this.state = new Backbone.Model({
selected: !!options.selected
});
this.listenTo(this.state, 'change:selected', this.renderSelectedState);
},
// ...
});
我建议不要在模型中存储任何与视图相关的属性,因为随着应用程序的增长,如果您在多个可选列表中显示相同的模型,它就不是一个可扩展的解决方案。但是...您可以覆盖模型的 toJSON 函数以删除您不想保留的属性:
ModelWithClientAttributes = Backbone.Model.extend({
toJSON: function(withClientAttrs) {
var json = Backbone.Model.prototype.toJSON.call(this);
if (withClientAttrs) return json;
return _(json).omit(this.clientAttrs);
},
// ...
});
// Extend from that base class when defining your model, and define the 'clientAttrs' property
Post = ModelWithClientAttributes.extend({
clientAttrs: ['selected', 'checked'],
// ...
});
// Then, in your view:
render: function() {
this.$el.html(
this.template(
this.model.toJSON( true )
)
);
}
// Backbone.sync will call toJSON without arguments, so they will receive the filtered json representation
var post = new Post({
selected: true,
title: 'May Snow Storm',
body: '...'
});
post.save();
console.log(post.toJSON()); // {"title": "May Snow Storm", "body": "..."}
console.log(post.toJSON(true)); // {"selected": true, "title": "May Snow Storm", "body": "..."}
可能最安全和最佳的解决方案是将您希望保留在服务器端代码中的属性简单地列入白名单。
【讨论】:
App.Session 模型 (App.Session = new Backbone.Model()),我可以在该模型上获取和设置属性,并监听对这些属性的更改。 Then whenever your list is rendered, it can query the selection from this model and render appropriately (var selected = App.Session.get('inboxSelected'); ...) and when the selection changes, save it back (App.Session.set('inboxSelected', ...)).如果您想在页面加载时保持不变,您甚至可以在 App.Session 中添加逻辑以将信息保存在 cookie 中。