1

I need to combine data from two different RESTful endpoints with backbone.js. I'm trying to use the Backbone.RelationalModel extension. So I have the following:

app.Pilots = Backbone.RelationalModel.extend({
    url: POST_SUBMITTER.root + 'cloud_base/v1/pilots',
    initialize: function(){
    }
});

app.Flight = Backbone.RelationalModel.extend({
    initialize: function(){
    },
    relations: [
      {
        type: Backbone.HasOne,
        key: 'pilot_id',
        relatedModel: app.Pilots,
    ],  
    wait: true
});

app.FlightList= Backbone.Collection.extend({
    model: app.Flight,
    url: POST_SUBMITTER.root + 'cloud_base/v1/flights',  
 }) ;   
        
app.FlightsView =  Backbone.View.extend({    
    el: '#flights', 
    localDivTag: '#addFlight Div',
    preinitialize(){
       this.collection = new app.FlightList();
    },     
initialize: function(){
    this.collection.fetch({reset:true});
    this.render();
    this.listenTo(this.collection, 'add', this.renderItem);
    this.listenTo(this.collection, 'reset', this.render);
  },
render: function(){
    this.collection.each(function(item){    
        this.renderItem(item);      
    }, this );
  },
renderItem: function(item){        
        var expandedView = app.FlightView.extend({ localDivTag:this.localDivTag });
        var itemView = new expandedView({
            model: item
        })
        this.$el.append( itemView.render().el);   
    }
});     

new app.FlightsView();

The flights model has a pointer to the pilots model via a key 'pilot_id'. The pilots model will have the name of the pilot. Somewhere in here backbone needs to fetch the pilot data from the Pilots RESTful endpoint. But I do not see where/how to trigger that fetch.

T J
  • 42,762
  • 13
  • 83
  • 138
magic
  • 37
  • 7

1 Answers1

0

I was not able to get Backbone.RelationalModel to work as I expected. So I dropped RelationalModel.

What I came up with is, I added a collection for the pilots model:

 app.PilotList= app.Collection.extend({
    model: app.Pilots,
    url: POST_SUBMITTER.root + 'cloud_base/v1/pilots?role=subscriber'
 }) ; 

(removing the URL from the Model.) then changed my initialize method in the FlightsView:

initialize: function(){
    // create the two collections
      this.pilots = new app.PilotList();
      this.collection = new app.FlightList();
     // fetch the collections separately 
     // async:false forces the app to wait until the fetch is complete. 
      this.pilots.fetch({reset:true, async:false} );
      this.collection.fetch({reset:true });    
      this.listenTo(this.pilots, 'reset', this.render);                
      this.render();
      this.listenTo(this.collection, 'add', this.renderItem);
      this.listenTo(this.collection, 'reset', this.render);
    },`

then in the render function I copy from the pilots collection to the flights collection using the 'pilot_id' from the flight model as my key into the pilots model:

      render: function(){
        this.collection.each(function(item){
          item.set({"p_first_name":this.pilots.findWhere({pilot_id:parseInt(item.get('pilot_id'),10)}).get("first_name")}, {silent: true }); 
          item.set({"p_last_name" :this.pilots.findWhere({pilot_id:parseInt(item.get('pilot_id'), 10) }).get("last_name")}, {silent: true } ); 
          this.renderItem(item);        
    }, this );
  },

Now my flight model has the first and last name of the pilot. The {silent:true} causes backbone to NOT trigger an event when the value is set. The pilot name will be ignored by the REST endpoint when it is received anyway. I can create and edit flights and not have to reload the Pilots collection. A new pilot can not be added via this interface and when one is added reloading the this app is no big deal for my application.
There may be a better way, but this works for me.

magic
  • 37
  • 7