Converting JSON data to a base model with a child collection
I am working with a Playlist object that has some properties defining itself as well as a PlaylistItem collection.
When I receive data from my server, I receive a JSON response in my client side success method:
success: function (data) {
console.log("JSON data:", data);
playlists = _.map(data, function (playlistConfig) {
return new Playlist(playlistConfig);
});
...
}
Here I am converting JSON data to Playlist objects. Each Playlist object is a .Model base.
This is what my data looks like:
And this is what the playlist constructor looks like:
return function(config) {
var playlist = new Playlist(config);
return playlist;
};
var Playlist = Backbone.Model.extend({
defaults: function() {
return {
id: null,
userId: null,
title: 'New Playlist',
selected: false,
position: 0,
shuffledItems: [],
history: [],
items: Backbone.Collection.extend({
model: PlaylistItem
})
};
},
...
}
My problem:
If I create a Playlist object with default values, it is initialized with an empty Backbone.Collection for the PlaylistItem. However, if I create a Playlist object with a collection already defined, I get the underlying array and not the Backbone.Collection. This is because I am working with JSON data from a server that has not yet been converted to Backbone objects. This data propagates to the playlist defaults and overwrites the Backbone.Collection object.
What is the correct way to initialize with a filled Backbone.Collection? I could write code in Initializes that checks the type of my items array and if it is not Backbone.Collection I could create a new Backbone.Collection and add items to it and then replace the old array with a new one, but that seems really hoakey ...
Don't define your PlalistItems collection inside default values, but in advance. Then create an initialization method in your playlist model, for example:
var PlaylistItems = Backbone.Collection.extend({
...
});
var Playlist = Backbone.Model.extend({
initialize: function() {
this.set('items', new PlaylistItems(this.items));
},
defaults: function() {
return {
id: null,
userId: null,
title: 'New Playlist',
selected: false,
position: 0,
shuffledItems: [],
history: [],
items: [] // don't define your PlaylistItems Collection here
};
}
});
Have a look at the fiddle here: http://jsfiddle.net/georgedyer/r2XKb/ (you need to open your console to see the collection)
Another problem I ran into was that after saving your model to the server, you get a response that will change your inline collection into a regular javascript array. To fix this, I had to override the parsing function in my model class as follows:
var model = backbone.Model.extend({
urlRoot : "/rest/model",
initialize: function(){
this.set("myCollection", new MyCollection(this.myArray));
},
defaults: {
myArray: []
},
parse: function(response){
this.set(response);
this.set("myArray", new MyCollection(response.myArray));
}
});