为什么默认集合属性不再是集合?
当您获取或创建新的Daymodel
我认为看起来像这样:
{
day: 1,
agenda : [{
title: "New Todo",
completed : false
}, {
title: "other Todo",
completed : false
}]
}
默认agenda
属性是Todocollection
首先被原始对象数组替换。骨干不知道这个agenda
是一个集合,不会自动填充它。
这就是 Backbone 所做的defaults创建模型时(第 401 行) https://github.com/jashkenas/backbone/blob/8ec88604732944f197b352a6be22c8216ea9d3a1/backbone.js#L401:
var defaults = _.result(this, 'defaults');
attrs = _.defaults(_.extend({}, defaults, attrs), defaults);
this.set(attrs, options);
_.extend({}, defaults, attrs)
把defaults
首先,但随后,它们被过去的覆盖attrs
.
如何在模型中使用集合?
以下是实现此目的的三种解决方案。仅使用其中之一,或根据以下内容创建您自己的。
最简单、最有效的方法是don't.
保持Todocollection
出于Daymodel
模型并仅在需要时创建集合,就像在假想 DayView
:
var DayView = Backbone.View.extend({
initialize: function() {
// create the collection in the view directly
this.agenda = new Todocollection(this.model.get('agenda'));
},
/* ...snip... */
});
然后,当您想要在模型中保留更改时,只需将集合模型放回到Daymodel
:
this.model.set('agenda', this.collection.toJSON());
将集合放入模型的属性中
您可以创建一个函数来延迟创建集合并将其作为属性保留在模型中,而不是属性,离开attributes
哈希干净.
var Daymodel = Backbone.Model.extend({
defaults: { day: 1, },
getAgenda: function() {
if (!this.agenda) this.agenda = new Todocollection(this.get('agenda'));
return this.agenda;
}
});
然后,模型控制该集合,并且可以轻松地与已共享该模型的所有内容共享该集合,每个实例仅创建一个集合。
保存模型时,您仍然需要将原始模型传回attributes
hash.
属性内的集合
您可以通过小的改变来完成您已经尝试做的事情。
-
切勿将物体放入defaults
...而不使用返回对象的函数。
var Daymodel = Backbone.Model.extend({
defaults: function() {
return {
day: 1,
agenda: new Todocollection()
};
},
});
否则,agenda
集合将在每个实例之间共享Daymodel
因为集合在创建时只创建一次Daymodel
class.
这也适用于对象文字、数组、函数(为什么你要把它放在defaults
反正?!)。
-
确保它始终是一个集合。
var Daymodel = Backbone.Model.extend({
defaults: { day: 1, },
initialize: function(attrs, options) {
var agenda = this.getAgenda();
if (!(agenda instanceof Todocollection)) {
// you probably don't want a 'change' event here, so silent it is.
return this.set('agenda', new Todocollection(agenda), { silent: true });
}
},
/**
* Parse can overwrite attributes, so you must ensure it's a collection
* here as well.
*/
parse: function(response) {
if (_.has(response, 'agenda')) {
response.agenda = new Todocollection(response.agenda);
}
return response;
},
getAgenda: function() {
return this.get('agenda');
},
setAgenda: function(models, options) {
return this.getAgenda().set(models, options);
},
});
-
确保它是可序列化的。
var Daymodel = Backbone.Model.extend({
/* ...snip... */
toJSON: function(options) {
var attrs = Daymodel.__super__.toJSON.apply(this, arguments),
agenda = attrs.agenda;
if (agenda) {
attrs.agenda = agenda.toJSON(options);
}
return attrs;
},
});
如果您将集合放入模型属性中,如上所述,这可以很容易地应用。
-
避免意外覆盖agenda
属性。
这与第 2 点是一致的,这就是它变得困难的地方,因为它很容易被忽视,或者其他人(或另一个库)可以在以后做到这一点。
可以覆盖save
and set
函数来添加检查,但从长远来看它变得过于复杂而没有太多好处。
模型中的集合有什么缺点?
我谈到了在模型中完全避免它,或者懒惰地创建它。这是因为如果实例化大量模型,它会变得非常慢;如果每个模型嵌套多次(具有模型集合的模型,具有其他模型集合的模型等),它会变得非常慢。
按需创建时,您仅在需要时使用计算机资源,并且仅用于所需的内容。例如,任何现在不在屏幕上的模型都不会创建其集合。
开箱即用的解决方案
也许要使其正常工作需要做太多工作,因此完整的解决方案可能会有所帮助,并且有几个。
- 骨干关系 http://backbonerelational.org/
- 主干嵌套 https://github.com/afeld/backbone-nested
- 主干嵌套模型 https://github.com/blittle/backbone-nested-models
- 主干深度模型 https://github.com/kahwee/backbone-deep-model