Backbone 模型 fetch() 未调用解析
Backbone model fetch() not calling parse
我有两个函数在 Backbone 模型上调用 fetch。第一个使用 id 创建模型的新实例并调用 fetch(),第二个使用 id 从集合中检索现有模型实例并调用 fetch()。在第一个中,模型的解析功能被触发,但在第二个中没有...我不知道为什么。
第一个(触发解析)
App.fetchItemById = function (id) {
App.myItem = new App.Item({id: id});
App.myItem.fetch({
traditional: true,
data: {
elements: 'all',
format:'json',
},
success: function(){
App.myItemView = new App.ItemView({
el: $('#active-item'),
model: App.myItem,
});
App.myItemView.render();
}
});
};
第二个(不触发解析)
App.fetchItemFromCollectionById = function (id) {
App.myItem = App.myItemCollection.get(id);
App.myItem.fetch({
traditional: true,
data: {
elements: 'all',
format:'json',
},
success: function(){
App.myItemView = new App.ItemView({
el: $('#active-item'),
model: App.myItem,
});
App.myItemView.render();
}
});
};
我读过的所有文档都说模型的解析函数总是在获取时调用。
有人知道为什么第二次没有触发解析吗?
这是模型定义:
App.Item = Backbone.Model.extend({
urlRoot: '/api/v1/item/',
defaults: {
},
initialize: function(){
},
parse : function(response){
console.log('parsing');
if (response.stat) {
if (response.content.subitems) {
this.set(‘subitems’, new App.SubitemList(response.content.subitems, {parse:true}));
delete response.content.subitems;
this
}
return response.content;
} else {
return response;
}
},
});
已修复,感谢 EMILE 和 COREY - 下面的解决方案
事实证明,当我第一次加载 App.MyItemCollection 时,集合中的模型只是通用模型,没有正确地转换为 App.Item 的实例。在集合定义中添加 "model: App.Item" 解决了这个问题。见下文:
原创
App.ItemList = Backbone.Collection.extend({
url: '/api/v1/item/',
parse : function(response){
if (response.stat) {
return _.map(response.content, function(model, id) {
model.id = id;
return model;
});
}
}
});
已更新,已解决问题
App.ItemList = Backbone.Collection.extend({
url: '/api/v1/item/',
model: App.Item,
parse : function(response){
if (response.stat) {
return _.map(response.content, function(model, id) {
model.id = id;
return model;
});
}
}
});
parse
仅在成功时调用 fetch
在Backbone source中可以看到parse
函数只有在fetch
异步请求成功时才会被调用
fetch: function(options) {
options = _.extend({parse: true}, options);
var model = this;
var success = options.success;
// The success callback is replaced with this one.
options.success = function(resp) {
// parse is called only if the fetch succeeded
var serverAttrs = options.parse ? model.parse(resp, options) : resp;
// ...snip...
// then the provided callback, if any, is called
if (success) success.call(options.context, model, resp, options);
};
wrapError(this, options);
return this.sync('read', this, options);
},
parse is called whenever a model's data is returned by the server, in
fetch
, and save
.
假设 fetch
失败,没有模型数据被服务器 return 编辑,因此不会调用解析。
要使 fetch
成功使用现有模型,默认行为要求模型在其 attributes
哈希中具有 id
。
cid
仅用于在本地区分模型,不能单独用于抓取。
A special property of models, the cid or client id is a unique
identifier automatically assigned to all models when they're first
created. Client ids are handy when the model has not yet been saved to
the server, and does not yet have its eventual true id, but already
needs to be visible in the UI.
确保集合使用我们自己的模型
由于 , if the model
property 未在 myItemCollection
集合上设置,因此将调用默认模型 parse
,而不是您的 App.Item
模型的 parse
。
不应在 parse
函数中实例化模型,因为它是集合的职责。
App.ItemList = Backbone.Collection.extend({
model: App.Item, // make sure to set this property
url: '/api/v1/item/',
parse : function(response){
if (response.stat) {
return _.map(response.content, function(model, id) {
model.id = id;
return model;
});
}
}
});
如果我们不在集合上设置 model
property,任何时候我们在集合上使用 add
或 set
,我们都会面临同样的问题我们的新模型将是 Backbone.Model
个实例,而不是 App.Item
个实例。
避免 parse
中的副作用
您的 parse
函数有一些您应该了解的代码味道:
parse
不应对模型产生任何副作用。它应该接收数据和 return 转换后的数据,就是这样。
- 它应该总是return数据。在你的情况下,它只有 returns 数据在一个条件下,并且 returns
undefined
否则。
- 使用
delete
效率低下,最好只return一个新对象。无论如何,这是您应该避免的另一个副作用。
小心嵌套模型和集合
也就是说,我看到您在解析中将集合嵌套在模型的 attributes
散列中。出于以下几个原因,我建议不要使用这种模式:
- 模型变得非常脆弱,您需要非常小心地始终调用
parse: true
,并且永远不要在模型外设置 subitems
。
- 它在创建模型后立即为子项创建所有模型,这对于很多模型来说效率低下。 延迟初始化 子项会有所帮助。
- 使用
default
现在更加复杂 因为您必须记住属性中有一个集合。
- 出于同样的原因,保存模型更复杂。
- 子项中的更改不会触发父模型中的事件。
我已经在这里回答了这些问题的多种解决方案:
- Bubble events of nested models and collections
您的 collection 可能未使用与其型号 属性 相同的型号 class。这就是为什么不会调用该特定模型的解析。
如果 model
属性 未设置为您期望的模型,它不会对该模型调用解析。默认情况下 collection 将使用 Backbone.Model.
MyItemCollection = Backbone.Collection.extend({
model: App.Item
});
你可能拥有的是这样的东西
MyItemCollection = Backbone.Collection.extend({
model: Backbone.Model.extend({
urlRoot: '/api/v1/item/'
})
});
我有两个函数在 Backbone 模型上调用 fetch。第一个使用 id 创建模型的新实例并调用 fetch(),第二个使用 id 从集合中检索现有模型实例并调用 fetch()。在第一个中,模型的解析功能被触发,但在第二个中没有...我不知道为什么。
第一个(触发解析)
App.fetchItemById = function (id) {
App.myItem = new App.Item({id: id});
App.myItem.fetch({
traditional: true,
data: {
elements: 'all',
format:'json',
},
success: function(){
App.myItemView = new App.ItemView({
el: $('#active-item'),
model: App.myItem,
});
App.myItemView.render();
}
});
};
第二个(不触发解析)
App.fetchItemFromCollectionById = function (id) {
App.myItem = App.myItemCollection.get(id);
App.myItem.fetch({
traditional: true,
data: {
elements: 'all',
format:'json',
},
success: function(){
App.myItemView = new App.ItemView({
el: $('#active-item'),
model: App.myItem,
});
App.myItemView.render();
}
});
};
我读过的所有文档都说模型的解析函数总是在获取时调用。
有人知道为什么第二次没有触发解析吗?
这是模型定义:
App.Item = Backbone.Model.extend({
urlRoot: '/api/v1/item/',
defaults: {
},
initialize: function(){
},
parse : function(response){
console.log('parsing');
if (response.stat) {
if (response.content.subitems) {
this.set(‘subitems’, new App.SubitemList(response.content.subitems, {parse:true}));
delete response.content.subitems;
this
}
return response.content;
} else {
return response;
}
},
});
已修复,感谢 EMILE 和 COREY - 下面的解决方案
事实证明,当我第一次加载 App.MyItemCollection 时,集合中的模型只是通用模型,没有正确地转换为 App.Item 的实例。在集合定义中添加 "model: App.Item" 解决了这个问题。见下文:
原创
App.ItemList = Backbone.Collection.extend({
url: '/api/v1/item/',
parse : function(response){
if (response.stat) {
return _.map(response.content, function(model, id) {
model.id = id;
return model;
});
}
}
});
已更新,已解决问题
App.ItemList = Backbone.Collection.extend({
url: '/api/v1/item/',
model: App.Item,
parse : function(response){
if (response.stat) {
return _.map(response.content, function(model, id) {
model.id = id;
return model;
});
}
}
});
parse
仅在成功时调用 fetch
在Backbone source中可以看到parse
函数只有在fetch
异步请求成功时才会被调用
fetch: function(options) {
options = _.extend({parse: true}, options);
var model = this;
var success = options.success;
// The success callback is replaced with this one.
options.success = function(resp) {
// parse is called only if the fetch succeeded
var serverAttrs = options.parse ? model.parse(resp, options) : resp;
// ...snip...
// then the provided callback, if any, is called
if (success) success.call(options.context, model, resp, options);
};
wrapError(this, options);
return this.sync('read', this, options);
},
parse is called whenever a model's data is returned by the server, in
fetch
, andsave
.
假设 fetch
失败,没有模型数据被服务器 return 编辑,因此不会调用解析。
要使 fetch
成功使用现有模型,默认行为要求模型在其 attributes
哈希中具有 id
。
cid
仅用于在本地区分模型,不能单独用于抓取。
A special property of models, the cid or client id is a unique identifier automatically assigned to all models when they're first created. Client ids are handy when the model has not yet been saved to the server, and does not yet have its eventual true id, but already needs to be visible in the UI.
确保集合使用我们自己的模型
由于 model
property 未在 myItemCollection
集合上设置,因此将调用默认模型 parse
,而不是您的 App.Item
模型的 parse
。
不应在 parse
函数中实例化模型,因为它是集合的职责。
App.ItemList = Backbone.Collection.extend({
model: App.Item, // make sure to set this property
url: '/api/v1/item/',
parse : function(response){
if (response.stat) {
return _.map(response.content, function(model, id) {
model.id = id;
return model;
});
}
}
});
如果我们不在集合上设置 model
property,任何时候我们在集合上使用 add
或 set
,我们都会面临同样的问题我们的新模型将是 Backbone.Model
个实例,而不是 App.Item
个实例。
避免 parse
中的副作用
您的 parse
函数有一些您应该了解的代码味道:
parse
不应对模型产生任何副作用。它应该接收数据和 return 转换后的数据,就是这样。- 它应该总是return数据。在你的情况下,它只有 returns 数据在一个条件下,并且 returns
undefined
否则。 - 使用
delete
效率低下,最好只return一个新对象。无论如何,这是您应该避免的另一个副作用。
小心嵌套模型和集合
也就是说,我看到您在解析中将集合嵌套在模型的 attributes
散列中。出于以下几个原因,我建议不要使用这种模式:
- 模型变得非常脆弱,您需要非常小心地始终调用
parse: true
,并且永远不要在模型外设置subitems
。 - 它在创建模型后立即为子项创建所有模型,这对于很多模型来说效率低下。 延迟初始化 子项会有所帮助。
- 使用
default
现在更加复杂 因为您必须记住属性中有一个集合。 - 出于同样的原因,保存模型更复杂。
- 子项中的更改不会触发父模型中的事件。
我已经在这里回答了这些问题的多种解决方案:
- Bubble events of nested models and collections
您的 collection 可能未使用与其型号 属性 相同的型号 class。这就是为什么不会调用该特定模型的解析。
如果 model
属性 未设置为您期望的模型,它不会对该模型调用解析。默认情况下 collection 将使用 Backbone.Model.
MyItemCollection = Backbone.Collection.extend({
model: App.Item
});
你可能拥有的是这样的东西
MyItemCollection = Backbone.Collection.extend({
model: Backbone.Model.extend({
urlRoot: '/api/v1/item/'
})
});