11

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?

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Alessandro Minoccheri
  • 35,521
  • 22
  • 122
  • 171
  • I've been following your other questions regarding this issue and it appears like you've got several issues that you are trying to work out. What you really need is the cartesian function that @Bergi suggested in this question http://stackoverflow.com/questions/17417589/recursive-function-jquery-with-backbone. I would continue down that path. – Brian Lewis Jul 03 '13 at 15:26
  • I have already tried but seems that doesn't work, array of first groupBy is empty I don't know why.. @moderndegree – Alessandro Minoccheri Jul 03 '13 at 15:28
  • I submitted an update to @Bergi's answer to this question (http://stackoverflow.com/questions/17417589/recursive-function-jquery-with-backbone). In the meantime, you can see a working example here: http://plnkr.co/edit/NHE9V5?p=preview. – Brian Lewis Jul 03 '13 at 17:11

1 Answers1

20

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'});
Brian Lewis
  • 5,739
  • 1
  • 21
  • 28
  • Hi I know this is an old answer but shouldn't rooms be added to `this.attributes` not just `this` as you can't do `model.get('rooms')` – Quince Oct 29 '14 at 18:25
  • 1
    This is because `rooms` is a Collection and needs to be addressed directly, rather than via `get()` or `set()`. For example, if you were to call `set('rooms', [])`, the Collection would be out of sync. I supposed you could rework it to listen to `change:rooms` and handle it that way but it just seemed like a lot of work. – Brian Lewis Oct 29 '14 at 18:50
  • If `rooms` is a collection inside your model attributes hash, you could just use `get('rooms').reset([])` to avoid out of sync collection and also avoid listening to it. – Emile Bergeron Apr 22 '16 at 14:48