Puigcerber
Puigcerber

Reputation: 10104

Backbone.js: this.model is undefined

I've spent the past two weeks trying to learn Backbone.js and then also modularizing the app with Require.js. But seems there are something that I'm not getting in the whole process of initialization and fetching.

I have two routes, one shows an entire collection while the other shows just an individual model. And I want to be able to start the app with any of both routes.

If I start loading the collections url and later on a single model url, everything works as expected. If I start the app with the url route to a single model I got the error: TypeError: this.model is undefined this.$el.html(tmpl(this.model.toJSON()));on the view.

If I set defaults for the model, it renders the view but doesn't fetch it with the real data. I've tried also to handle the success event in the fetch function of the model without any luck.

router.js

define(['jquery','underscore','backbone','models/offer','collections/offers','views/header','views/event','views/offer/list', 
], function($, _, Backbone, OfferModel, OffersCollection, HeaderView, EventView, OfferListView){

var AppRouter = Backbone.Router.extend({    

routes: {
    'event/:id' : 'showEvent',
  '*path': 'showOffers'
},

initialize : function() {       
    this.offersCollection = new OffersCollection();
    this.offersCollection.fetch();
    var headerView = new HeaderView();
    $('#header').html(headerView.render().el);          
},

showEvent : function(id) {
    if (this.offersCollection) {
        this.offerModel = this.offersCollection.get(id);
    } else {
        this.offerModel = new OfferModel({id: id});
        this.offerModel.fetch();
    }       
    var eventView = new EventView({model: this.offerModel});    
    $('#main').html(eventView.render().el);     
},

showOffers : function(path) {
    if (path === 'betting' || path === 'score') {
        var offerListView = new OfferListView({collection: this.offersCollection, mainTemplate: path});  
      $('#main').html(offerListView.render().el) ;       
    }       
},    
});

var initialize = function(){    
  window.router = new AppRouter;
  Backbone.history.start();
};

return {
  initialize: initialize
};
});

views/event.js

define(['jquery','underscore','backbone','text!templates/event/main.html',
], function($, _, Backbone, eventMainTemplate){

var EventView = Backbone.View.extend({
    initalize : function(options) {
        this.model = options.model; 
        this.model.on("change", this.render);       
    },

    render : function() {
        var tmpl = _.template(eventMainTemplate);
        this.$el.html(tmpl(this.model.toJSON()));
        return this;
    }
});

return EventView;   
});

Upvotes: 0

Views: 2626

Answers (1)

Paul Hoenecke
Paul Hoenecke

Reputation: 5060

You are creating and fetching the OffersCollection in initialize method of the router, so the else block in showEvent will never be hit since this.offersCollection is always truthy.

After the comments, I think you need to do this:

showEvent : function(id) {
    var that = this;
    var show = function(){
       var eventView = new EventView({model: that.offerModel});    
       $('#main').html(eventView.render().el); 
    };
    // offersCollection is always defined, so check if it has the model
    if (this.offersCollection && this.offersCollection.get(id)) {
        this.offerModel = this.offersCollection.get(id);
        show();
    } else {
        this.offerModel = new OfferModel({id: id});
        this.offerModel.fetch().done(function(){
           // model is fetched, show now to avoid your render problems.
           show();
        });
        // alternatively, set the defaults in the model,
        // so you don't need to wait for the fetch to complete.
    }       

}

Upvotes: 1

Related Questions