Backbone-relational
Backbone-relational copied to clipboard
Parse data of a hasMany relationship by its associated collection
It would be great if models in a hasMany relationship could be parsed by the corresponding collection model. Here is an example:
var MyModel = Backbone.Model.extend({
relations : [
type: Backbone.HasMany,
key : 'hasManyRelation',
relatedModel : 'MyModel',
collectionType : 'MyModelCollection',
parseCollection : true // <--- unfortunately this does not exist
],...
});
...
var MyModelCollection = Backbone.Collection.extend({
parse: function (resp) {
this.metadata = resp.metadata;
return resp.items;
},
)}
The data returned by the server:
{
metadata : { ... }
items : {
id : 1,
attribute : "123",
hasManyRelation : {
metadata : { ... }
items : [...]
}
}
}
I'm having the same issue. My use case is that my collections return data as paged collections. The actual array is a "data" property of the returned data.
The response for the object with a collection of children looks like:
{
/* model properties */
"children":
{
"paged": false,
"rowCount": null,
"hasMore": false,
"maxRows": null,
"offset": 0,
"data": [ /* models are here */ ]
}
}
My collection has a parse method:
parse: function(response)
{
if (response["data"] != null)
{
var t = this;
$.each(["offset", "maxRows", "hasMore", "paged"],
function(i, prop)
{
t[prop] = response[prop];
});
this._loadedPages[Math.floor(this.offset / this.maxRows)] = true;
if (this.hasMore == false && Number.isInteger(this.rowCount) == false &&
response.data.length)
{
this.rowCount = this.offset + response.data.length;
}
else if (Number.isInteger(response["rowCount"]))
{
this.rowCount = response.rowCount;
}
return response["data"];
}
return response;
},
The problem is that when this collection is loaded as a relation, the parse method is never called. In this use case I don't care about having parse called on the model, I only need it called on the collection.
Found a work-around for those that may want it.
In your model (not the collection), implement a parse method:
parse: function(response, options)
{
var children = response.children;
if (children && children.data)
{
collection = new CustomCollection();
items = collection.parse(children);
collection.reset(items, { silent: true });
response.children = collection;
}
return response;
},
The backbone-relational code already checks to see if the items are a Backbone collection before parsing them in fetchRelated, so by pre-parsing them it avoids the issue.
Not pretty but it does work around the issue.