Jannick
Jannick

Reputation: 2134

Backbone.js: Dynamically adding events not firing

I am trying around with Backbone.js and get along so far, but I have got a problem.

Lets say I got a root element and a child element.

When the document loads, I create 3 "root" instances. The root instance appends a tag. Each root instance creates one child instance which creates a

  • tag in the ul tag.

    Now I would like the child instance to attach and onclick event to the

  • tag. Unfortunately, it won't work.

    I created a fiddle:

    http://jsfiddle.net/Fluxo/sEjE5/17/

    var child = Backbone.View.extend({
        template: _.template('<li>Item '+count+'</li>'),
        events: {
            'click li': function() {
             alert('listitem Click Child Element');   
            }
        },
        initialize: function() {
          _.bindAll('render');  
         this.render();   
        }, render: function() {
            this.$el.html(this.template())
        }
    });
    
    var root = Backbone.View.extend({
        template: _.template('<div><h3>List</h3><p /><ul></ul><hr />'),
        events: {
            'click li': function() {
             alert('listitem Click - Root Element');   
            }
        },
        initialize: function() {
            _.bindAll('render');
            this.render();
        },
        render: function() {
            this.$el.html(this.template());
            $('body').append(this.el);
            var item = new child();
            this.$el.find('ul').append(item.$el.html());
    
        }
    });
    

    The events created in the root element will fire, but not the ones in the child element.

    Am I doing anything wrong?

    Upvotes: 1

    Views: 3096

  • Answers (1)

    mu is too short
    mu is too short

    Reputation: 434665

    You're doing two things wrong.

    First of all, your child is an <li>, it doesn't contain an <li>:

    template: _.template('<li>Item '+count+'</li>'),
    events: {
        'click li': ...
    },
    

    so your click li event won't do anything. Events are bound to the view's el using delegate:

    delegateEvents delegateEvents([events])

    Uses jQuery's delegate function to provide declarative callbacks for DOM events within a view. [...] Omitting the selector causes the event to be bound to the view's root element (this.el).

    So if you want to bind a click handler directly to the view's el rather than one of its children, you want to leave out the selector:

    events: {
        'click': ...
    }
    

    The next problem is that you're not actually inserting the child element into the DOM, you're copying the HTML:

    this.$el.find('ul').append(item.$el.html());
    

    By appending item.$el.html() instead of item.el, you're grabbing the correct HTML as a string and inserting that HTML but you lose the events in the process; the events are bound to the DOM object, item.el, not to the HTML string. You can fix this by appending item.el:

    this.$el.find('ul').append(item.el);
    // Or you could say, the two approaches are the same
    this.$('ul').append(item.el);
    

    Demo: http://jsfiddle.net/ambiguous/K76JM/ (or http://jsfiddle.net/ambiguous/kFxHQ/)

    Upvotes: 5

    Related Questions