Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding render callback in Backbone.js

Tags:

backbone.js

According to Backbone.js documentation:

Whenever a UI action causes an attribute of a model to change, the model triggers a "change" event; all the Views that display the model's data are notified of the event, causing them to re-render.

So I suppose that render() method should be bound to "change" event by default. However the following code does not work:

TestModel = Backbone.Model.extend({});
TestView  = Backbone.View.extend({
    render: function() {
        alert('render called');
    }
});
var mod  = new TestModel;
var view = new TestView({model:mod});
mod.change();

It works only if I add explicit bind call:

initialize: function() {
    this.model.bind('change', this.render, this);
}

Does this mean that my understanding of default render() callback is not correct and we should always bind render() callback by hand?

like image 254
grigy Avatar asked Jan 04 '12 18:01

grigy


2 Answers

Unless something has changed in the last few months, yes, that is the case. This is a good thing, as it gives flexibility as to when views are rendered/re-rendered (for example, some applications might want to render a view only after a model has been persisted on the server, not necessarily when it changes in the browser). If you want your views to always re-render when a model attribute changes, you can extend the default backbone view with your own base view that binds its render method to the model change event, then extend all your concrete views from that. Ex:

MyView = Backbone.View.extend({
    initialize: function() {
        Backbone.View.prototype.initialize.apply(this, arguments);
        this.model.bind('change', this.render);
    }
});

MyConcreteView = MyView.extend({...});
var model = new Backbone.Model({...});
var view = new MyConcreteView({model: model});
model.set({prop: 'value'});
like image 95
rr. Avatar answered Oct 04 '22 10:10

rr.


You can redefine the Backbone.View constructor to set the render callback by default after creating a new view using the code beneath:

Backbone.View = (function(View) {
  // Define the new constructor
  Backbone.View = function(options) {
    // Call the original constructor
    View.apply(this, arguments);
    // Add the render callback
    if (this.model != null) {
      this.model.bind("change", this.render, this);
    } else {
      // Add some warning or throw exception about 
      // the render callback not being triggered
    }
  };
  // Clone static properties
  _.extend(Backbone.View, View);
  // Clone prototype
  Backbone.View.prototype = (function(Prototype) {
    Prototype.prototype = View.prototype;
    return new Prototype;
  })(function() {});
  // Update constructor in prototype
  Backbone.View.prototype.constructor = Backbone.View;
  return Backbone.View;
})(Backbone.View);

Now you can create a new view like so:

view = new Backbone.View({model: new Backbone.Model})
like image 31
Samuel Avatar answered Oct 04 '22 10:10

Samuel