Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lifecycle of a Backbone.js View during its creation

I'm new to backbone.js, and somewhat new to front-end work as well and haven't yet quite figured out how the lifecycle works.

We have a Django backend, which provides us with html templates, which we basically only use as frames. All the logic is handled in Backbone views.

The problem that I currently have is that I'm trying to draw a graph but the graphing function doesn't find the view based on the id as it doesn't exist during the render function, but I'm unaware of a way to achieve this at a later phase.

I've tried to create the view manually in Chrome console after the page has completely loaded and it works:

   var main = new MainView();
   main.showChart();

The View:

   var ChartView = Backbone.View.extend({

     title: 'Chart',

     initialize: function() {

    // This assures that this refers to this exact view in each function
    // (except within asynchronous functions such as jquery each)
    _.bindAll(this);

    // Saving parameters given by parent
    this.index = this.options.index;

    // Retrieve the template from server
    var template = _.template(getTemplate('chart.html'));

    // Compile the template with given parameters
    var compiledTemplate = template({'title': this.title});

    // Set the compiled template to this instance's el-parameter
    this.$el.append(compiledTemplate);

    // Rendering the view
    this.render();
 },

   render: function() {

    var self = this;

    // Draw the graph when the page is ready
    $(function(){
        self.drawGraph('chart1', this.line1Data);
    });

    // Render function should always return the instance
    return this;
},

drawGraph : function(chartId, lineData) {

    Morris.Line({
          element: chartId,
          data: [
            {y: '2012', a: 100},
            {y: '2011', a: 75},
            {y: '2010', a: 50},
            {y: '2009', a: 75},
            {y: '2008', a: 50},
            {y: '2007', a: 75},
            {y: '2006', a: 100}
          ],
          xkey: 'y',
          ykeys: ['a'],
          labels: ['Series A']
    });
},

});

Where it's created:

     var chartWidgetView = new WidgetView({'contentView': new ChartView()});
    this.initializeWidget(chartWidgetView);
    this.$el.append(chartWidgetView.el);

Could someone clarify to me:

  1. How does Backbone actually handle the creation of a view? What are the different stages?
  2. How should I handle this situation, e.g. at which point of my code would the element from the html template exist so that I could call the graphing function for it?
  3. Or is my architecture just fundamentally flawed? Should I try to do this in some completely different way?
like image 978
jesseniem Avatar asked Aug 14 '12 20:08

jesseniem


People also ask

How does BackboneJS work?

BackboneJS provides various building blocks such as models, views, events, routers and collections for assembling the client side web applications. When a model changes, it automatically updates the HTML of your application. BackboneJS is a simple library that helps in separating business and user interface logic.

What is the architecture of BackboneJS?

It is based on the Model-View Controller framework that binds data, which is abstracted into models, and DOM which is abstracted into views, using events. It is a JavaScript library. Applications of Backbone. js: Following are the applications of Backbone.

What are the main components of BackboneJS?

Unlike most of the MVC frameworks, Backbone. js consists of six main components: Models, Views, Collections, Events, Routers and Sync.


2 Answers

FWIW, I think you're on the right track. But as your question notes, you've just got a few things out of order.

Strictly speaking, there isn't much of a life cycle built in to backbone views. When you instantiate one, it calls initialize. Other than that, it's up to you to decide what the lifecycle of the view will be. When it will be rendered. When the rendered el will be attached to the DOM, when it will be removed from the DOM, when it will be closed down and destroyed. That all depends on how you want to work with the view.

There are some things you do and add on to make this lifecycle easier to understand, of course. There are a few great frameworks that sit on top of backbone, for example. I recommend looking at LayoutManager, Thorax, Chaplin, and my own Marionette as starting points for this.

More to the point of your question, though, the plugin that you're describing is very likely dependent on the HTML elements being in the DOM before the plugin can run. This is common for visual plugins as they often need to capture location information, css information, positions of relative items, etc.

There are some very simple things you can do to facilitate these types of plugins and make this work. I've blogged about it a little, here: http://lostechies.com/derickbailey/2012/02/20/using-jquery-plugins-and-ui-controls-with-backbone/ - hopefully that will help get you down the path.

Specifically, what you'll want to look at is the idea of an onShow method. This isn't a method that Backbone understands on it's own. It's a concept that you'll have to add to your views and your apps. But the good news is that it's easy. Just add the method to your view, then call it at the right time:


var AnotherView = Backbone.View.extend({
  onShow: function(){
    this.$el.layout({ appDefaultStyles: true});
  }
});


// instantiate the view
var view = new AnotherView();

// render it
view.render();

// attach it to the DOM
$("#someDiv").html(view.el);

// now that it has been attached to the DOM
// you can call your DOM-dependent plugins
view.onShow();

Hope that helps.

like image 108
Derick Bailey Avatar answered Oct 06 '22 01:10

Derick Bailey


Just glancing at this I think the problem is that the template is not returned from the server before you render it, hence it doesn't appear. You can get around this problem using jQuery's deferred object (see this ref). Try doing something like at the end of initialize:

this.deferredTemplate = $el.append(compiledTemplate);

this.deferredTemplate.done(function() {
  this.render();
});

See also Derick Bailey's article on deferreds in backbone.js: http://lostechies.com/derickbailey/2012/02/09/asynchronously-load-html-templates-for-backbone-views/

like image 38
Chris Salzberg Avatar answered Oct 05 '22 23:10

Chris Salzberg