Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

populating nested collections with parent model fetch

I've got the following model with nested collection

var Mdl = Backbone.Model.extend({
  initialize: function() {

    // collection
    this.col1 = new NestedCollection();

  },
  ...
});

I would like to send the data for both the model and the models in the collection in one request looking something like:

{
  att1: val,
  col1: [{obj1: val}, {...}]
}

I'm unsure about the best way to hand the data in the request to the nested collection (col1). I can't do ...

var Mdl = Backbone.Model.extend({
  initialize: function() {
    // collection
    this.col1 = new NestedCollection(this.get('col1');
  },
  ...
});

... because at the time of initialize is called the parse function of the model has not been called which means that the attribute col1 is empty, another solution I thought of was to listen for the change in the parent model like...

model.bind("change:tags", function() {
  model.col1.refresh(model.get('col1'));
});

however this solution feels a little heavy handed and might potentially break any

this.col1.bind("add", function() {})

and

this.col1.bind("remove", function() {})

function set-up on the collection.

Has anyone got any idea of the 'official' way of doing this?

Thanks.

like image 984
luxerama Avatar asked Jun 09 '11 12:06

luxerama


1 Answers

The "official" way is to override the parse method:

http://documentcloud.github.com/backbone/#Model-parse

In your specific case, what I would probably do is, in the parse method, build the nested collection from the col1 data, delete it from the results, then hand the results on. Backbone will then turn the rest of the data into properties.

I have not tried this, so I'm not 100% sure it works:

parse: function(response) {
  this.col1 = new NestedCollection(response.col1);
  delete response.col1
  return response
}

Edit: Nov 28th 2012

Harm points out that this might not be the best way to do it any more. The original answer was written quite a while ago, and the original question indicated that the user wanted the collection to be a property on the model (not an attribute), but Harm has a point that having the collection as an attribute is a more accepted way of doing it these days.

Today, you could use something like Backbone-Relational to handle a lot of this stuff for you, or, if you wanted to do it yourself, and have the collection as a model attribute, you could do something like:

Building = Backbone.Model.extend({
    parse: function(response) {
        console.log("Parse Called");
        response.rooms = new Rooms(response.rooms);
        return response;
    }
});
Room = Backbone.Model.extend({});
Rooms = Backbone.Collection.extend({
    model: Room
});

science_building = new Building();

science_building.fetch(
    {success: function(model,resp) {console.log(resp);}}
);

With a model fetch response like:

{ id: 1, 
  name: "Einstein Hall", 
  rooms: [
    {id:101, name:'Chem Lab'},
    {id:201, name:'Physics Lab'},
    {id:205, name:'Bio Lab'}
  ]
}

Resulting in a Building model that allows:

science_building.get('rooms').get(101).get('name')   // ==> "Chem Lab"

A working jsFiddle example: http://jsfiddle.net/edwardmsmith/9bksp/

like image 50
Edward M Smith Avatar answered Oct 11 '22 13:10

Edward M Smith