在我的应用程序中,我正在尝试使用Firebase来存储基于骨干框架的实时数据。
问题是这样的:
我有一个子级模型和集合,它们都是通用骨干模型和集合。
var Todo = Backbone.Model.extend({
defaults: {
title: "New Todo",
completed : true
}
});
var Todocollection = Backbone.Collection.extend({
model: Todo,
initialize: function() {
console.log("creating a todo collection...");
},
});
然后有一个高级模型,它包含sublevel集合作为属性。
var Daymodel = Backbone.Model.extend({
defaults : {
day: 1,
agenda : new Todocollection()
}
});
然后对于更高级别的集合,我将firebase集合
var DayCollection = Backbone.Firebase.Collection.extend({
model: Daymodel
});
到目前为止,我可以正确地将数据添加到更高级别的集合,该集合具有day
属性和agenda
属性(应该是TodoCollection
)。
问题是当我尝试将数据添加到子级别集合时,它无法正常工作。
this.collection.last()
.get("agenda")
.add({
title: this.input.val(),
completed: false
});
上面的代码将在View部分中。 this.collection.last()
将获得最后一个模型。 get("agenda")
应该是集合对象。
但它不起作用。该错误表明this.collection.last(...).get(...).add
不是函数。
调试后,我发现this.collection.last().get("agenda")
返回一个通用JS对象而不是集合对象。
我进一步调试了如果我使用骨干集合作为外部集合DayCollection
。一切都很顺利。
如何解决这个问题?
答案 0 :(得分:3)
当您获取或创建新的Daymodel
时,我认为它是这样的:
{
day: 1,
agenda : [{
title: "New Todo",
completed : false
}, {
title: "other Todo",
completed : false
}]
}
首先是agenda
的默认Todocollection
属性被原始对象数组取代。 Backbone不知道agenda
是一个集合,不会自动填充它。
这就是Backbone对defaults
at model creation (line 401)所做的事情:
var defaults = _.result(this, 'defaults'); attrs = _.defaults(_.extend({}, defaults, attrs), defaults); this.set(attrs, options);
_.extend({}, defaults, attrs)
首先放置defaults
,然后,它们会被传递的attrs
覆盖。
以下是实现此目的的三种解决方案。只使用其中一个,或根据以下内容创建自己的。
将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
哈希。
您可以通过微小的更改来完成您已经尝试做的事情。
切勿将对象放入defaults
...而不使用返回对象的函数。
var Daymodel = Backbone.Model.extend({
defaults: function() {
return {
day: 1,
agenda: new Todocollection()
};
},
});
否则,agenda
集合将在Daymodel
的每个实例之间共享,因为在创建Daymodel
类时仅创建一次集合。
这也适用于对象文字,数组,函数(为什么你还要把它放在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点并列,因为它很容易被忽视,或者其他人(或其他lib)可以做到这一点。
可以覆盖save
和set
函数来添加检查,但从长远来看,它会变得过于复杂而没有太大的好处。
我谈到完全在模型中避免它,或者懒洋洋地创建它。那是因为如果你实例化很多模型会变得非常慢,如果每个模型多次嵌套,模型会慢一些(具有模型集合的模型,还有其他模型集合等)。
按需创建时,您只需在需要时使用机器资源,并且仅在需要时使用。例如,现在不在屏幕上的任何模型都不会创建它们的集合。
也许让这项工作正常工作太多了,所以一个完整的解决方案可能有所帮助,而且还有一对。