Search code examples
javascriptbackbone.jsbackbone.js-collections

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?


Solution

  • 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'});