50

I'm trying to figure out how to make a Collection of collections with backbone.js. I'm pretty new to backbone. I have something like the following situation:

 +---------------+               +------------------+
 | Playlists     |               | Playlist         |
 |---------------|          0..* |------------------|
 |               +-------------->| Name             |
 |               |               |                  |
 |               |               |                  |
 +---------------+               +-------+----------+
                                         |
                                         |
                                         |0..*
                                         v
                                 +------------------+
                                 |  Track           |
                                 |------------------|
                                 | Name             |
                                 | Artist           |
                                 |                  |
                                 +------------------+

In code this looks similar to this:

var trackModel = Backbone.Model.extend({
    //trackdata
});

var playlistModel = Backbone.Collection.extend({
    model : trackModel,
    url   : "playlist"
});

var playlistsModel = Backbone.Collection.extend({
    url   : "playlists",
    model : playlistModel   //This pretty sure doesn't work like I want, because there is no model attribute for collections :S
});

However I always receive an error in the js console saying:

 Uncaught TypeError: Object [object Object] has no method '_validate'

when I try to execute a function that triggers the validate (like add, fetch, ...)

It makes no difference if i add the validate or _validate function to any of the collections or models.

I believe this is because backbone.js doesn't support collections in collections. Is there another way that works?

UPDATE:

This is how it looks right now

var Track = Backbone.Model.extend({ 
    //trackdata 
}); 

var Tracks = Backbone.Collection.extend({ 
    model:Track; 
}); 

var Playlist = Backbone.Model.extend({ 
    //name  : ...
    tracks: new Tracks ()
}); 

var Playlists = Backbone.Collection.extend({ 
    url : "playlists", 
    model : Playlist 
});
T J
  • 42,762
  • 13
  • 83
  • 138
krial
  • 842
  • 1
  • 7
  • 15
  • Looks like the backbone docs now include a section on nested models & collections, very similar to the example here: http://backbonejs.org/#FAQ-nested – Idris Mokhtarzada Aug 20 '13 at 17:14
  • First - glad you solved your problem. Hopefully this will be answer for some others, but your problem arrives from wrongly defining data model - there is no "playlists" (you just have many playlist object, that are grouped into one place), your data contains only "playlist" and "track", and there is relation 1 playlist can have many tracks. In your simple (solved) example this pattern is visible pretty clear. – Dainius May 18 '15 at 19:02

1 Answers1

30

You'd solve your problem by turning your Playlist from a collection into a model. If you think about it, a Playlist would probably have other attributes anyway (e.g. name) that wouldn't be settable on a collection.

Playlists would then be a collection of Playlist models (instead of collections), which should work without error.

var Track = Backbone.Model.extend({
    //trackdata
});

var Playlist = Backbone.Model.extend({
    model : Track
});

var Playlists = Backbone.Collection.extend({
    url   : "playlists",
    model : Playlist
});
Rob Hruska
  • 118,520
  • 32
  • 167
  • 192
  • Thank you, seems to work perfectly :D However I needed a supplement collection, because a Playlist can have multiple tracks: var Track = Backbone.Model.extend({ //trackdata }); var Tracks = Backbone.Collection.extend({ model:Track; }); var Playlist = Backbone.Model.extend({ model : Tracks }); var Playlists = Backbone.Collection.extend({ url : "playlists", model : Playlist }); I hope everything will work without problems with the synchronization with a server. – krial Apr 30 '12 at 19:01
  • I'm not sure that approach will work - you simply can't set an extension of `Backbone.Collection` (i.e. `Tracks`) as the model of another collection. You'll still want to keep `Track` as your `Playlist.model`, and you can still use a `Tracks` collection to help facilitate the syncing, though. – Rob Hruska Apr 30 '12 at 19:14
  • I have updated the code in the question.I didn't set a collection as the model of another collection. I set the colelction(Tracks) as an attribute of the model Playlist(extends model). If I would have done it like you said in the answer: `Playlist->model: track`, I could only store one track inside the playlist, because Playlist extends Model and a Model has no methods to make a collection of the attribute Model... Or am I wrong? – krial May 01 '12 at 08:59
  • Now, i'm having a problem when trying to fetch a playlist from the server. The server response to the fetch is similar to the following: `{"name":"Track Search", "mObjs":[{ "trackName":"unknown", "artistName":"unknown"}]}` The problem is, that Backbonejs interprets the [] as an array instead of a collection. As a result, the attribute "tracks" of the Model Playlist will no more contain a Tracks Collection, but a simple javascript Array – krial May 08 '12 at 18:28
  • 2
    @krial - That's expected. Backbone doesn't handle associations. You'll either have to use [a plugin](https://github.com/PaulUithol/Backbone-relational) or manually create the `Collection` in your Model's [`parse`](http://documentcloud.github.com/backbone/#Model-parse) or [`initialize`](http://documentcloud.github.com/backbone/#Model-constructor) method. That's probably material for a different question. – Rob Hruska May 08 '12 at 18:32