javascriptbackbone.jsbackbone-views

Bind click event to top level tag of Backbone view


I'm attempting to bind a click event to the top level tag of my backbone view. It currently looks like this:

var PageSize = Backbone.View.extend({

    tagName: 'option',
    className: "setPageSize",

    initialize: function(options) {
        this.value = options.value;
        this.text = options.text;
    },

    template: _.template(
        "<%=text%>"
    ),

    render: function() {

        this.$el.html(this.template({text: this.text}));
        return this;
    },

    events: {
        'click .setPageSize': 'setPageSize'
    },

    setPageSize: function() {
        console.log(this.value);
    },

});

module.exports = PageSize;

A bunch of these PageSize views are instantiated by another view, which appends them to a <select> tag. I'm fairly certain the other view isn't the problem, as the <option> tags do show up in the <select> tag with the proper text.

The issue I'm having is that the click event, which should fire when a given <option> tag is clicked, never fires. I think it's because the class that the click event watches is part of the outermost tag (the one specified with tagName and className), which for some reason doesn't have the event listener attached to it.

I think I need to somehow bind the click event to the entire view rather than to the template items within it, but I'm totally unsure as to how I'd go about doing that. I've tried doing this.setElement(this.$el.html()) but doing so makes it so none of the <option> tags show up in the <select> at all.


Solution

  • From the backbone docs delegateEvents (emphasis added by me)

    Uses jQuery's on function to provide declarative callbacks for DOM events within a view. If an events hash is not passed directly, uses this.events as the source. Events are written in the format {"event selector": "callback"}. The callback may be either the name of a method on the view, or a direct function body. Omitting the selector causes the event to be bound to the view's root element (this.el).

    The problem is in your events object. Basically because you added a "class selector" the click event is only going to get handled for elements within the view's element that have the class ".setPageSize". However that class is on the view's element itself but not on any of it's children, so the handler never gets called.

    By changing this:

    events: {
        'click .setPageSize': 'setPageSize'
    },
    

    to this:

    events: {
        'click': 'setPageSize'
    },
    

    causes the event to be bound to the view's root element (this.el). In other words the view itself.