我在模型中有一个集合,如下图所示:
var itemModel = Backbone.Model.extend({
defaults:{
name:"",
brand:"",
priceCollection:[]
}
})
附加到itemModel
的更改侦听器也会更改附加到集合的侦听器
在视图中this.listenTo(itemModel.get('priceCollection'),'change',this.dosomething)
。
问题是,如果通过{{1}为模型提供了一组新属性,只要父模型没有改变,集合上的更改侦听器就可以正常工作 itemModel.get(' priceCollection')上绑定的事件将丢失。
我如何保留此活动?或者我应该在模型每次更改时重新绑定此事件?或者我应该将集合上的侦听器从视图移动到模型并触发自定义Backbone事件吗?
应该注意,这个模型是单身
答案 0 :(得分:1)
请记住,Backbone假设Collection和Model应该以1:1的比例映射到服务器端资源。它明确了解API布局和数据结构 - 请参阅Model.url
,Model.urlRoot
和Collection.url
。
你说模特是单身人士。在这种情况下,我建议分别维护模型和集合。
由于SomeModel
没有伴随紧密关系的某个集合SomeCollection
,因此没有必要在属性级别上将它们关联起来。建立事件监听器和同步数据所需的工作只在一个地方。
// some controller (app main)
var model = new SomeSingletonModel();
var collection = new SomeSingletonCollection();
var view = new SomeView({
model: model,
collection: collection
});
映射到SomeSingletonModel
的资源可能会传送一个数组。
使用普通数组作为模型属性(model.get("name")
是什么)使用集合有什么好处?同步和更改事件。两者都可能只在View更新Collection的模型时才需要。当View仅渲染时,Collection在许多情况下不会提供任何好处。
如果需要更新该阵列的数据,由于Backbone的同步机制,使用Collection可能是正确的选择。
但是如何保持集合与模型同步(你问)?
您的控制器需要收听模型并更新sync
和reset
上的集合:
model.on("sync reset", function() {
// "priceCollection" is a model attribute
collection.reset(model.get("priceCollection"));
// optionally unset "priceCollection" on the model
this.unset("priceCollection", { silent: true });
});
这将初始化集合。
对Collection的模型的任何更改都只是Collection或Model的同步机制的一部分。
答案 1 :(得分:1)
另见my other answer,当模型是单身时,这可能是更好的选择。
请注意关于Backbone在该答案上对API设计的假设的第一个声明。
注意:如有必要,在所有这些实现中,集合的url
或模型(集合的模型)url
/ rootUrl
可能会在sync
上得到(重新)定义控制同步。
此实现删除模型属性并使用其数据更新对象属性。
对象属性是一个仅在模型更改时重置但未重新创建的Collection实例。
var CustomModel = Backbone.Model.extend({
defaults: {
// defaults go here - "children" may be contained here
},
// implement constructor to act before the parent constructor is able to
// call set() (L402 in v1.3.0) with the initial values
// See https://github.com/jashkenas/backbone/blob/1.3.0/backbone.js#L402
constructor: function() {
// create children collection as object attribute - replaces model attr.
this.children = new Backbone.Collection();
// listen to changing events to catch away that attribute an update the
// object attribute
this.listenTo(this, "change:children sync reset", this.onChangeColl);
// apply original constructor
Backbone.Model.apply(this, arguments);
},
onChangeColl: function() {
// check for presence since syncing will trigger "set" and then "sync",
// the latter would then empty the collection again after it has been updated
if (this.has("children")) {
// update "children" on syncing/resetting - this will trigger "reset"
this.children.reset(this.get("children"));
// remove implicitly created model attribute
// use silent to prevent endless loop due to change upon change event
this.unset("children", { silent: true });
}
}
});
在小提琴或控制台中测试时的示例用法:
var c = new CustomModel({ a: 1, children: [{ x: 1 }, { x: 5 }] });
c.set({a: 8, children: [{ x: 50 }, { x: 89 }]});
c.url = "/dummy"
// replace sync() only for fetch() demo - the implementation does what sync() would do on success
c.sync = function(method, coll, opts){ if (method == "read") { opts.success({ a: 100, children: [{ x: 42 }, { x: 47 }] }); } }
c.fetch();
临
此实现拦截模型属性更改,并使用已使用原始数据初始化(重置)的Collection实例替换其数据。
var CustomModel = Backbone.Model.extend({
defaults: {
// this is optional
children: new Backbone.Collection()
},
initialize: function() {
// listen to model attribute changing events to swap the raw data with a
// collection instance
this.listenTo(this, "change:children sync reset", this.onChangeColl);
},
onChangeColl: function() {
if (this.has("children")) {
// use silent to prevent endless loop due to change upon change event
this.set("children", new Backbone.Collection(this.get("children")), { silent: true });
}
}
});
在小提琴或控制台中测试时的示例用法:
var c = new CustomModel({ a: 1, children: [{ x: 1 }, { x: 5 }] });
c.set({ a: 8, children: [{ x: 50 }, { x: 89 }] });
c.url = "/dummy";
// replace sync() only for fetch() demo - the implementation does what sync() would do on success
c.sync = function(method, coll, opts){ if (method == "read") { opts.success({ a: 100, children: [{ x: 42 }, { x: 47 }] }); } }
c.fetch();
临
注意:根据您的要求和API设计,您可能不希望children
自动同步到服务器。在这种情况下,该解决方案是有限的您可以覆盖模型的toJSON()
,但这可能会限制其对应用程序其他部分的使用(例如将数据提供到视图中)。
也许您的主要数据实际上是收藏品。因此,使用其他数据来装饰集合是另一种方法。此实现提供了Collection中的一个模型,该模型将在收集同步时更新。
此实现最适合于获取集合数据以及属性(例如,使用目录本身的属性获取目录内容)。
var CustomCollection = Backbone.Collection.extend({
initialize: function() {
// maintain decorative attributes of this collection
this.attrs = new Backbone.Model();
},
parse: function(data, opts) {
// remove "children" before setting the remainder to the Model
this.attrs.set(_.omit(data, "children"));
// return the collection content only
return data.children;
}
});
在小提琴或控制台中测试时的示例用法:
var c = new CustomCollection({ a: 1, b: 2, children: [{ x: 2 }, { x: 3 }] }, { parse: true });
c.reset({ a: 9, b: 11, children: [{ x: 5 }, { x: 10 }] } , { parse: true });
// replace sync() only for fetch() demo - the implementation does what sync() would do on success
c.sync = function(method, coll, opts){ if (method == "read") { opts.success({ a: 100, b: 124, children: [{ x: 42 }, { x: 47 }] }) } }
c.fetch();
临
parse()
实施哪个
- 反过来要求parse: true
始终传递给reset()
和set()
和
- 要求parse()
以集合作为范围(this
)进行调用(通过使用parse
initialize
定义this
,可以避免这种情况。绑定()')