Alessandro Minoccheri Alessandro Minoccheri - 12 days ago 5
Javascript Question

Backbone nested collection

I have an app in backbone that retrieve data from a server. This data are hotels and foreach hotel I have more rooms. I have divided hotel into a json and rooms inside another json like this:

hotel.json

[
{
"id": "1",
"name": "Hotel1"
},
{
"id": "2",
"name": "Hotel2"
},
{
"id": "3",
"name": "Hotel3"
}
]


rooms.json

[
{
"id" : "r1",
"hotel_id" : "1",
"name" : "Singola",
"level" : "1"
},
{
"id" : "r1_1",
"hotel_id" : "1",
"name" : "Doppia",
"level" : "2"
},
{
"id" : "r1_3",
"hotel_id" : "1",
"name" : "Doppia Uso singol",
"level" : "1"
},
{
"id" : "r2",
"hotel_id" : "2",
"name" : "Singola",
"level" : "1"
},
{
"id" : "r2_1",
"hotel_id" : "2",
"name" : "Tripla",
"level" : "1"
}
]


I wanna take each hotel and combine with its rooms (external key into
rooms.json
hotel_id
) and print the combination of the rooms: foreach level combine different rooms.

One room of level 1, one room of level 2 and one room of level 3.

Maximum of level is 3 but I can have only one level or only two level.
If I have 3 level I don't want combination of level 1 and level 2 without level 3.

Something like this

Room "Single", "level" : "1" , "hotel_id" : "1"
Room "Double", "level" : "2" , , "hotel_id" : "1"
Room "Triple", "level" : "3" , , "hotel_id" : "1"





Room "Double for single", "level" : "1" , "hotel_id" : "1"
Room "Double", "level" : "2" , , "hotel_id" : "1"
Room "Triple", "level" : "3" , , "hotel_id" : "1"


The constructor of this rooms I think is to put into renderRooms into my app.

This is my app:

var Room = Backbone.Model.extend();
var Rooms = Backbone.Collection.extend({
model: Room,
url: "includes/rooms.json"
});
var Hotel = Backbone.Model.extend({
defaults: function() {
return {
"id": "1",
"name": "Hotel1",
"rooms": []
}
}
});
var HotelCollection = Backbone.Collection.extend({
model: Hotel,
url: "includes/test-data.json",
initialize: function() {
console.log("Collection Hotel initialize");
}
});
var HotelView = Backbone.View.extend({
template: _.template($("#hotel-list-template").html()),
initialize: function() {
this.collection = new HotelCollection();
this.collection.bind('sync', this.render, this);
this.collection.fetch();
},
render: function() {
console.log('Data hotel is fetched');
this.bindRoomToHotel();
var element = this.$el;
element.html('');
},
bindRoomToHotel: function() {
allRooms = new Rooms();
allRooms.on("sync", this.renderRooms, this)
allRooms.fetch();
},
renderRooms: function() {


$(this.el).html(this.template({ hotels: this.collection.models }));
}
});

var hotelView = new HotelView({
el: $("#hotel")
});


How can I create this room combination and print it?

Is there a good way or there is something better?

Answer

Here is how you can structure the Collections:

HotelModel = Backbone.Model.extend({
    initialize: function() {
        // because initialize is called after parse
        _.defaults(this, {
            rooms: new RoomCollection
        });
    },
    parse: function(response) {
        if (_.has(response, "rooms")) {
            this.rooms = new RoomCollection(response.rooms, {
                parse: true
            });
            delete response.rooms;
        }
        return response;
    },
    toJSON: function() {
        var json = _.clone(this.attributes);
        json.rooms = this.rooms.toJSON();
        return json;
    }
});

RoomModel = Backbone.Model.extend({
});

HotelCollection = Backbone.Collection.extend({
    model: HotelModel
});

RoomCollection = Backbone.Collection.extend({
    model: RoomModel
});

Then you can do something like this:

var hotels = new HotelCollection();
hotels.reset([{
    id: 1,
    name: 'Hotel California',
    rooms: [{
        id: 1,
        name: 'Super Deluxe'
    }]
}], {
    parse: true // tell the collection to parse the data
});

// retrieve a room from a hotel
hotels.get(1).rooms.get(1);

// add a room to the hotel
hotels.get(1).rooms.add({id:2, name:'Another Room'});