How to render a view when model is fetched from multiple urls

I am working in project with backbone.js and the problem I am facing is that I have a model that doesn't need to be in sync with the server, this model its only intended to fetch user data to initialize the rest of the views, it is kind of a wrapper view for the app with a model attached to it.

This model fetch its data from multiple urls and my actual problem is that the view is rendering before all the data is assigned to the model in some cases and in other cases is rendered when all the data is already assigned to the model.

i am using $.when() to fetch the model and calling .done() to render the view but i think i don't understand the concept of the defer object. Would like to know what kind of suggestion you guys have in order to proceed with this problem. I leave you an example on how is my code.

Model

      var userModel = Backbone.Model.extend({
        url: "/api/vacationtypes.json",
        defaults: {
          userName: 'anonymous',
          availableDays: 0,
          vacationType: []
        },

        initialize: function() {
          var that = this;
          _.bindAll(this,'parseAvailableDays');
        },

        parse: function(data){
          return {vacationType: data.data}
        },

        getAvailableDays: function() {
          $.ajax({
            url: "/api/staffAvailableDays/get/" + Zvacations.session.email + ".json",
            success: this.parseAvailableDays
          });
        },

        parseAvailableDays: function(response) {
          this.set('availableDays', response.data[0].availableDays);
        }

      });

View

  var Home = Backbone.View.extend({
    tagName: "section",
    className: "home",
    el: "#request-form"

    events: {
         // events for the view
    },

    initialize: function(){
      var that = this;
      this.setPageTitle('Home');
      this.model.on('change:availableDays', this.render, this);
      //  once all fetches for model are done render the view (sometime execute before the succes of getAvailableDays)
      $.when( this.model.fetch(), this.model.getAvailableDays() ).done(function(){
        that.render();
      });
    },

    render: function(){
      var template = _.template(homeViewTemplate, this.model.toJSON());
      this.$el.html(template);
      // get holydays from db
      this.getHolidays();
      //assign total steps after render
      this.totalSteps = $(homeViewTemplate).find('fieldset').length
      // initialize jQuery UI datepicker
      this.dateSelectorView();

      return this;
    },

    // here goes rest of the view methods          

   }); 

Hope you guys can help me figuring out which one is the best way to wait untill all fetch is done to render.

Upvotes: 0

Views: 87

Answers (1)

dehrg
dehrg

Reputation: 1741

You need to return the jqXHR (ajax return value) from getAvailableDaysso that it can be used with $.when

getAvailableDays: function() {
  return $.ajax({
    url: "/api/staffAvailableDays/get/" + Zvacations.session.email + ".json",
    success: this.parseAvailableDays
  });
},

Your existing code passes the return value of getAvailableDays and fetch to $.when. When you don't return anything from getAvailableDays your code is equivalent to the following:

$.when(this.model.fetch(), undefined).done(function() {
    that.render();
});

Which ignores the ajax call inside of getAvailableDays.

From the jQuery documentation:

If a single argument is passed to jQuery.when() and it is not a Deferred or a Promise, it will be treated as a resolved Deferred and any doneCallbacks attached will be executed immediately

You will find in the Backbone internals that fetch returns the jqXHR object from the ajax call, similar to what you should be doing with getAvailableDays

Upvotes: 2

Related Questions