Many of my Backbone models often deal with nested models and collections, so far I'm using a combination of defaults
, parse
and toJSON
manually to achieve nesting:
ACME.Supplier = Backbone.Model.extend({
defaults: function() {
return {
contacts: new ACME.Contacts(),
tags: new ACME.Tags(),
attachments: new ACME.Attachments()
};
},
parse: function(res) {
if (res.contacts) res.contacts = new ACME.Contacts(res.contacts);
if (res.tags) res.tags = new ACME.Tags(res.tags);
if (res.attachments) res.attachments = new ACME.Attachments(res.attachments);
return res;
}
});
ACME.Tag = Backbone.Model.extend({
toJSON: function() {
return _.pick(this.attributes, 'id', 'name', 'type');
}
});
I've looked at a few plugins out there that basically does the same as above but with a lot less control and more boilerplate, so I'm wondering if anyone has a more elegant solution to this common Backbone.js problem.
Edit: I ended up with the following approach:
ACME.Supplier = Backbone.Model.extend({
initialize: function(options) {
this.tags = new ACME.Tags(options.tags);
},
parse: function(res) {
res.tags && this.tags.reset(res.tags);
return res;
}
});
ACME.Tag = Backbone.Model.extend({
toJSON: function() {
return _.pick(this.attributes, 'id', 'name', 'type');
}
});
It is worth noting that later I discovered that you'll need to pass nested model/collection data from the constructor into the constructor of the nested model via the options
object.
We didn't want to add another framework to achieve that so we abstracted it away in a base model class. Here's how you declare and use it (available as a gist):
It works equally well with
set
andtoJSON
.And here's
BaseModel
:I don't see any problem with your approach.
IMHO the
Model.parse()
method if for this: to be overwritten in case special parse behavior needs.The only think I'd change would be things like this:
For this:
Due you already have an instance of
ACME.Tags
collection I'd reuse it.Also I don't really like the
defaults
implementation, I'm used to do this initializations in theModel.initialize()
but I think is a matter of taste.I'v found out that with this approach Supplier's toJSON function will get outdated, so it might be a good idea to do reassemble back it's JSON state from it's, and it's children's data.
});
Faced with the same problem, I do something like that (the code below is output of TypeScript compiler so it's a bit verbose):
And then I can simply override the fieldToType method to define types of my fields: