Search code examples
backbone.jsviewrenderingbackbone-viewsviewrendering

How to ensure that Backbone has rendered the page completely?


I work on a large enterprise application with BackboneJS. One page in the application is constructed using multiple sub-system calls via REsT. How do I make sure that, all the services required to load the page has been called and the templates are binding is completed?

For example, I have a MasterView, that takes care of the collection.fetch() of each child views, like this.  

myApp.views.MasterView = Backbone.View.extend({
    initialize: function(params) {
        var self = this;
        this.collection.fetch({
            success: function(resp) {
                self.collection.bind("reset", self.render(), self);
            },
            error: function(xhr, xhrStatus) {
                // push error message, in case of fetch fails.
            }
        });
    },
    render: function() {
        var self = this;
        this.collection.each(function(model) {
            if (model.get('authorize') && model.get('status') === "success" && model.get('data').length > 0) {
                self.bindTemplate(model.get('data')[0]);
            }
        });
    }
});

I have a view set for the page, that takes care of rendering two other views CustomerInfo and CustomerAccounts. The view goes like this.

myApp.views.CustomerView = Backbone.View.extend({
        initialize: function() {
            var customerInfo = new myApp.collection.CustomerInfo();
            new myApp.views.CustomerInfo({el: $("#infoContainer"), collection: customerInfo});

            var customerAccount = new myApp.collection.CustomerAccount();
            new myApp.views.CustomerAccount({el: $("#accountContainer"), collection: customerAccount});
        }
});

  And CustomerInfo and CustomerAccount views, looks like this,  

myApp.views.CustomerInfo = myApp.views.MasterView.extend({
    initialize: function() {
        var self = this;
        myApp.views.MasterView.prototype.initialize.call(self, {
            qParam1: "qparam1",
            qParam2: "qparam2"
        });
    },
    render: function() {
        var self = this;
        self.template = _.template(myApp.Templates.get("customer-page/customer-info"));
        myApp.views.MasterView.prototype.render.apply(self);
    },
    bindTemplate: function(data) {
        var self = this;
        $(self.el).html(self.template({"info": data}));
    }
});
 
myApp.views.CustomerAccounts = myApp.views.MasterView.extend({
    initialize: function() {
        var self = this;
        myApp.views.MasterView.prototype.initialize.call(self, {
            qParam1: "qparam1"
        });
    },
    render: function() {
        var self = this;
        self.template = _.template(myApp.Templates.get("customer-page/customer-accounts"));
        myApp.views.MasterView.prototype.render.apply(self);
    },
    bindTemplate: function(data) {
        var self = this;
        $(self.el).html(self.template({"accounts": data}));
    }
});

  I would like to know if there is any way to know from the myApp.views.CustomerView that the views CustomerInfo and CustomerAccounts has completed its rendering? The main problem I have here is the CustomerInfo view loads quickly but the CustomerAccount view takes some time to load. Hence I need to display the page on one shot, when both the views are ready on DOM.


Solution

  • After breaking my head for quite sometime, and searching on Google, I found this link.

    So I made few changes to my MasterView and it was working and have solved the problem I had. The change I made in the MasterView is this

    var activeConnections=0;
    
    myApp.views.MasterView = Backbone.View.extend({
        initialize: function(params) {
    
            activeConnections++;
    
            var self = this;
            this.collection.fetch({
                success: function(resp) {
    
                    activeConnections--;
    
                    self.collection.bind("reset", self.render(), self);
    
                    if(activeConnections===0){
                        // trigger the page has finished rendering
                    }
                },
                error: function(xhr, xhrStatus) {
                    // push error message, in case of fetch fails.
                    if(activeConnections===0){
                        // trigger the page has finished rendering
                    }
                }
            });
        },
        render: function() {
            var self = this;
            this.collection.each(function(model) {
                if (model.get('authorize') && model.get('status') === "success" && model.get('data').length > 0) {
                    self.bindTemplate(model.get('data')[0]);
                }
            });
        }
    });
    

    Thanks to all those who have helped me solve this.