Backbone refresh view events

11,157

Solution 1

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;                            
                }

Solution 2

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.
Share:
11,157
keepyourweb
Author by

keepyourweb

Updated on June 15, 2022

Comments

  • keepyourweb
    keepyourweb almost 2 years

    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;