嵌套在 firebase 集合模型中的集合没有添加功能
The collection nested inside firebase collection's model doesn't have add function
在我的应用程序中,我尝试使用 Firebase 来存储基于 backbone 框架的实时数据。
问题是这样的:
我有一个子级别模型和集合,它们都是通用 backbone 模型和集合。
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...");
},
});
然后是高级模型,其中包含子级集合作为属性。
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
});
以上代码将在视图部分内。 this.collection.last()
将获得最后一个模型。 get("agenda")
应该是集合对象。
但是不行。错误显示 this.collection.last(...).get(...).add
不是函数。
调试后发现this.collection.last().get("agenda")
returns是一个普通的JS对象,而不是集合对象
我进一步调试如果使用backbone集合作为外层集合DayCollection
。一切顺利。
如何解决这样的问题?
为什么默认的 collection 属性不再是 collection?
当您获取或创建一个新的 Daymodel
时,我认为它看起来像这样:
{
day: 1,
agenda : [{
title: "New Todo",
completed : false
}, {
title: "other Todo",
completed : false
}]
}
最初是 Todocollection
的默认 agenda
属性被替换为 object 的原始数组。 Backbone 不知道 agenda
是 collection 并且不会自动填充它。
这就是 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
.
覆盖
如何在模型中使用 collection?
以下是实现此目的的三种解决方案。仅使用其中之一,或根据以下内容创建您自己的。
最简单有效的方法是不要。
将 Todocollection
排除在 Daymodel
模型之外,只在需要时才创建 collection,就像 假设的 DayView
:
var DayView = Backbone.View.extend({
initialize: function() {
// create the collection in the view directly
this.agenda = new Todocollection(this.model.get('agenda'));
},
/* ...snip... */
});
然后,当您想要在模型中保留更改时,只需将 collection 模型放回 Daymodel
:
this.model.set('agenda', this.collection.toJSON());
将collection放入模型属性中
您可以创建一个函数来延迟创建 collection 并将其作为 属性、 保留在模型中 attributes
哈希清理.
var Daymodel = Backbone.Model.extend({
defaults: { day: 1, },
getAgenda: function() {
if (!this.agenda) this.agenda = new Todocollection(this.get('agenda'));
return this.agenda;
}
});
然后,该模型控制 collection,它可以轻松地与已经共享该模型的所有对象共享,每个实例只创建一个 collection。
保存模型时,您仍然需要将原始模型传回 attributes
哈希。
一个collection里面的属性
您可以完成您已经尝试做的小改动。
切勿将 object 放入 defaults
...而不是使用返回 object 的函数。
var Daymodel = Backbone.Model.extend({
defaults: function() {
return {
day: 1,
agenda: new Todocollection()
};
},
});
否则,agenda
collection 将在 Daymodel
的每个实例之间共享,因为 collection 在创建 Daymodel
[ 时仅创建一次=144=].
这也适用于 object 字面量、数组、函数(你为什么要把它放在 defaults
中?!)。
确保它始终是 collection.
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;
},
});
如果您将 collection 放入模型 属性 中,这很容易应用,如上文所述。
避免意外覆盖 agenda
属性。
这与第 2 点并存,这就是它变得越来越难的地方,因为它很容易被忽视,或者其他人(或其他库)可能会这样做。
可以重写 save
和 set
函数来添加检查,但是它变得过于复杂而在长 运行.
模型中 collection 的缺点是什么?
我谈到了在模型中完全避免它,或者懒惰地创建它。那是因为如果你实例化很多模型,它会变得非常慢,如果每个模型嵌套多次(模型有 collection 个模型,有其他 collection 个模型,等等) .
按需创建时,您仅在需要时才使用机器资源,并且仅在需要时才使用。例如,任何现在不在屏幕上的模型都不会创建 collection。
开箱即用的解决方案
也许要让它正常工作需要太多工作,所以一个完整的解决方案可能会有所帮助,而且有几个。
在我的应用程序中,我尝试使用 Firebase 来存储基于 backbone 框架的实时数据。
问题是这样的:
我有一个子级别模型和集合,它们都是通用 backbone 模型和集合。
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...");
},
});
然后是高级模型,其中包含子级集合作为属性。
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
});
以上代码将在视图部分内。 this.collection.last()
将获得最后一个模型。 get("agenda")
应该是集合对象。
但是不行。错误显示 this.collection.last(...).get(...).add
不是函数。
调试后发现this.collection.last().get("agenda")
returns是一个普通的JS对象,而不是集合对象
我进一步调试如果使用backbone集合作为外层集合DayCollection
。一切顺利。
如何解决这样的问题?
为什么默认的 collection 属性不再是 collection?
当您获取或创建一个新的 Daymodel
时,我认为它看起来像这样:
{
day: 1,
agenda : [{
title: "New Todo",
completed : false
}, {
title: "other Todo",
completed : false
}]
}
最初是 Todocollection
的默认 agenda
属性被替换为 object 的原始数组。 Backbone 不知道 agenda
是 collection 并且不会自动填充它。
这就是 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
.
如何在模型中使用 collection?
以下是实现此目的的三种解决方案。仅使用其中之一,或根据以下内容创建您自己的。
最简单有效的方法是不要。
将 Todocollection
排除在 Daymodel
模型之外,只在需要时才创建 collection,就像 假设的 DayView
:
var DayView = Backbone.View.extend({
initialize: function() {
// create the collection in the view directly
this.agenda = new Todocollection(this.model.get('agenda'));
},
/* ...snip... */
});
然后,当您想要在模型中保留更改时,只需将 collection 模型放回 Daymodel
:
this.model.set('agenda', this.collection.toJSON());
将collection放入模型属性中
您可以创建一个函数来延迟创建 collection 并将其作为 属性、 保留在模型中 attributes
哈希清理.
var Daymodel = Backbone.Model.extend({
defaults: { day: 1, },
getAgenda: function() {
if (!this.agenda) this.agenda = new Todocollection(this.get('agenda'));
return this.agenda;
}
});
然后,该模型控制 collection,它可以轻松地与已经共享该模型的所有对象共享,每个实例只创建一个 collection。
保存模型时,您仍然需要将原始模型传回 attributes
哈希。
一个collection里面的属性
您可以完成您已经尝试做的小改动。
切勿将 object 放入
defaults
...而不是使用返回 object 的函数。
var Daymodel = Backbone.Model.extend({ defaults: function() { return { day: 1, agenda: new Todocollection() }; }, });
否则,
agenda
collection 将在Daymodel
的每个实例之间共享,因为 collection 在创建Daymodel
[ 时仅创建一次=144=].这也适用于 object 字面量、数组、函数(你为什么要把它放在
defaults
中?!)。确保它始终是 collection.
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; }, });
如果您将 collection 放入模型 属性 中,这很容易应用,如上文所述。
避免意外覆盖
agenda
属性。这与第 2 点并存,这就是它变得越来越难的地方,因为它很容易被忽视,或者其他人(或其他库)可能会这样做。
可以重写
save
和set
函数来添加检查,但是它变得过于复杂而在长 运行.
模型中 collection 的缺点是什么?
我谈到了在模型中完全避免它,或者懒惰地创建它。那是因为如果你实例化很多模型,它会变得非常慢,如果每个模型嵌套多次(模型有 collection 个模型,有其他 collection 个模型,等等) .
按需创建时,您仅在需要时才使用机器资源,并且仅在需要时才使用。例如,任何现在不在屏幕上的模型都不会创建 collection。
开箱即用的解决方案
也许要让它正常工作需要太多工作,所以一个完整的解决方案可能会有所帮助,而且有几个。