Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone view event not firing - not sure why

I'm trying to get the click event to fire, but it's not working. Maybe someone can see something I can't.

ConnectionView = GlobalView.extend({
    tagName: 'div',

    events: {
        "click .social-links": "check"
    },

    initialize: function() {
        this.render();

        this.model.bind("change", this.render);
    },

    render: function() {
        // Compile the template using underscore
        var template = _.template($("#connection-template").html(), this.model.toJSON());

        // Load the compiled HTML into the Backbone "el"
        $(this.el).html(template);        
    },

    check: function(e) {
        e.preventDefault();

        alert("woot");
    }
});

Here is the template that it's pulling:

<script id="connection-template" type="text/template">
    <a id="link-<%= alt %>" class="social-links" href="<%= url.replace('||state||', state).replace('||timestamp||', time) %>">add <%= name %></a>
</script>

Here is the view that puts the ConnectionView into the DOM:

ConnectionsView = GlobalView.extend({
    tagName: 'div',

    initialize: function(){
        this.collection.bind("reset", this.render, this);
    },

    render: function(){        
        var $connections = $("<div class='external-accounts'>");

        this.collection.each(function (model) {            
            var conn = new ConnectionView({model: model});
            $connections.append(conn.el);
        });

        // Compile the template using underscore
        var template = _.template($("#connections-template").html());
        // Load the compiled HTML into the Backbone "el"
        $(this.el).html(template({
            connectionsList: $connections.outer()
        }));
    },

    destroy: function() {
        this.constructor.__super__.destroy.apply(this);

    }
});
like image 815
xil3 Avatar asked Jun 26 '12 16:06

xil3


1 Answers

Your problem is how you're filling in your ConnectionsView's el. You're doing this:

// Load the compiled HTML into the Backbone "el"
$(this.el).html(template({
    connectionsList: $connections.outer()
}));

I have no idea what .outer() is all about but it doesn't matter that much. The important thing is that everything is going through the compiled Underscore template() function and that means that everything will end up getting converted to strings along the way into the page. Once your DOM elements in $connections are in a string, the event bindings are lost and nothing works anymore.

Consider this example:

http://jsfiddle.net/ambiguous/4tjTm/

In there we do this:

var $connections = $('<div>');
var conn = new ConnectionView({ model: m });
$connections.append(conn.el);

var template = _.template('<%= connectionsList %>');
$('#view-goes-here').append(template({
    connectionsList: $connections.html()
}));

to add your ConnectionView to the page. The events don't work in there because template() returns a string and that string gets parsed into DOM elements which end up in the page. But, if we add the $connections straight to the page:

http://jsfiddle.net/ambiguous/AKkCJ/

using something like this:

var $connections = $('<div>');
var conn = new ConnectionView({ model: m });
$connections.append(conn.el);
$('#view-goes-here').append($connections);

the events work as expected.

So now we know what went wrong. But how do we fix it? All we need to do is adjust your ConnectionsView to add $connections directly to the DOM with something like this:

render: function() {
    // Move <div class='external-accounts'> into your #connections-template.
    var template = _.template($("#connections-template").html());
    this.$el.html(template());
    var $external = this.$el.find('.external-accounts');
    this.collection.each(function (model) {
        var conn = new ConnectionView({model: model});
        $external.append(conn.el);
    });
    return this; // This is conventional
}

Push the <div class="external-accounts"> into the ConnectionsView template and insert the ConnectionViews directly into it. This way you're always working with DOM elements, strings don't know about events but DOM elements do.

like image 63
mu is too short Avatar answered Sep 27 '22 20:09

mu is too short