Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone refresh view events

In my view I don't declare this.el because I create it dinamically, but in this way the events don't fire.

This is the code:

View 1:

App.Views_1 = Backbone.View.extend({

    el:             '#content',

    initialize:     function() {    
                        _.bindAll(this, 'render', 'renderSingle');                          
                    },

    render:         function() {    
                        this.model.each(this.renderSingle);                 
                    },

    renderSingle:   function(model) {

                        this.tmpView = new App.Views_2({model: model});                     
                        $(this.el).append( this.tmpView.render().el );

                    }
});

View 2:

App.Views_2 = Backbone.View.extend({

    initialize:     function() {                                
                        _.bindAll(this, 'render');                      
                    },

    render:         function() {    
                        this.el = $('#template').tmpl(this.model.attributes);       // jQuery template                          
                        return this;                            
                    },

    events:         {       
                        'click .button' :       'test'                  
                    },

    test:           function() {        
                        alert('Fire');  
                    }

    });

});

When I click on ".button" nothing happens. Thanks;

like image 479
keepyourweb Avatar asked Aug 31 '11 17:08

keepyourweb


2 Answers

At the end of your render() method, you can tell backbone to rebind events using delegateEvents(). If you don't pass in any arguments, it will use your events hash.

render:         function() {    
                    this.el = $('#template').tmpl(this.model.attributes);       // jQuery template                          
                    this.delegateEvents();
                    return this;                            
                }
like image 133
Edward M Smith Avatar answered Oct 17 '22 13:10

Edward M Smith


As of Backbone.js v0.9.0 (Jan. 30, 2012), there is the setElement method to switching a views element and manages the event delegation.

render: function() {
    this.setElement($('#template').tmpl(this.model.attributes));
    return this;
}

Backbone.View setElement: http://backbonejs.org/#View-setElement

setElementview.setElement(element)

If you'd like to apply a Backbone view to a different DOM element, use setElement, which will also create the cached $el reference and move the view's delegated events from the old element to the new one.



Dynamically creating your views in this fashion has it's pros and cons, though:

Pros:

  • All of your application's HTML markup would be generated in templates, because the Views root elements are all replaced by the markup returned from the rendering. This is actually kind of nice... no more looking for HTML inside of JS.
  • Nice separation of concerns. Templates generate 100% of HTML markup. Views only display states of that markup and respond to various events.
  • Having render be responsible for the creation of the entire view (including it's root element) is in line with the way that ReactJS renders components, so this could be a beneficial step in the process of migrating from Backbone.Views to ReactJS components.

Cons: - these are mostly negligible

  • This wouldn't be a painless transition to make on an existing code base. Views would need to be updated and all templates would need to have the View's root elements included in the markup.
    • Templates used by multiple views could get a little hairy - Would the root element be identical in all use cases?
  • Prior to render being called, the view's root element is useless. Any modifications to it will be thrown away.
    • This would include parent views setting classes/data on child view elements prior to rendering. It is also bad practice to do this, but it happens -- those modifications will be lost once render overrides the element.
  • Unless you override the Backbone.View constructor, every view will unnecessarily delegate it's events and set attributes to a root element that is replaced during rendering.
  • If one of your templates resolves to a list of elements rather than a single parent element containing children, you're going have a bad time. setElement will grab the first element from that list and throw away the rest.
    • Here's an example of that problem, though: http://jsfiddle.net/CoryDanielson/Lj3r85ew/
    • This problem could be mitigated via a build task that parses the templates and ensures they resolve to a single element, or by overriding setElement and ensuring that the incoming element.length === 1.
like image 30
Cory Danielson Avatar answered Oct 17 '22 14:10

Cory Danielson