Ben_hawk
Ben_hawk

Reputation: 2486

backbone.js view event does not execute

I have the following backbone.js view shown below. It was working fine, and now the click event does not execute when the form button is clicked. No errors in console, or any other obvious signs of why is shown.

window.FormOptionView = Backbone.View.extend({
    template: _.template($('#test-option').html()),
    render: function (eventName) {
        $('#test1').append(this.template(this.model.toJSON()));
         $('#test2').append(this.template(this.model.toJSON()));
        return this;
    }

});


window.AddTestView = Backbone.View.extend({

    template: _.template($('#test-add').html()),

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

    },

    events: {
             "click button": "addTest" 
    },

    addTest: function(event){
        event.preventDefault();
        var test = new Test({
            test1: {
                firstName: $("#test1 option:selected").val(),
                lastName: $("#test1Score").val()
            },
            test2: {
                firstName: $("#test2 option:selected").val(),
                lastName: $("#test2Score").val()
            }
        });

        test.add(result);
        app.navigate("tests", true);

    },

    render: function (eventName) {
        $('#content').html(this.template());
        _.each(this.collection.models, function (test) {
             this.renderSelectBox(test);
        }, this);
        return this;
    },

    renderSelectBox: function (item) {
       var optionView = new FormOptionView({
           model: item
       });
       $(this.el).append(optionView.render().el);
    }
});

The corrosponding HTML

        <script type="text/template" id="test-option">
        <option><%= firstName %> <%= lastName %></option>
    </script>

    <script type="text/template" id="test-add">

                <form id="addTest" action="#">
                        <label for="test1">Test1:</label>

                        <select id="test1">
                            <option></option>
                        </select>

                        <label for="test1Score">Score:</label>

                        <input id="test1Score" type="number" />



                        <label for="test2">Test 2:</label>

                        <select id="test2">
                            <option></option>
                        </select>

                        <label for="test2Score">Score:</label>

                        <input id="test2Score" type="number" />


                        <button id="add">Add</button>
                    </form>

           </script>

Upvotes: 0

Views: 480

Answers (3)

mu is too short
mu is too short

Reputation: 434915

Your problem, as you've already discovered, is that your view wasn't handling its el properly.

When your view is rendered, Backbone hooks up the events by using jQuery's delegate on the view's this.el.

If you don't explicitly set the el (through the constructor as new V({ el: ... }), in the view's definition as el: ..., or by calling setElement), then the el will be constructed using various view properties as noted in the documentation; the default el is just a simple <div>. This is where your empty <div>s are coming from.

You were doing this:

render: function (eventName) {
    $('#content').html(this.template());
    _.each(this.collection.models, function (test) {
         this.renderSelectBox(test);
    }, this);
    return this;
}

and somewhere else you were probably doing a simple add_test_view.render(). The result is that the event delegate is bound to the view's el (an empty <div>) and that el is never added to the DOM; if you have delegate bound to something that isn't in the DOM then you never get any events.

If you say el: '#content' in your view definition, then Backbone will use #content as your el and your view would look more like this:

el: '#content',
//...
render: function (eventName) {
    this.$el.html(this.template());
    this.collection.each(function(test) {
        this.renderSelectBox(test);
    }, this);
    return this;
},
renderSelectBox: function (item) {
    var optionView = new FormOptionView({
        model: item
    });
    this.$el.append(optionView.render().el);
}

Notice that I switch to this.collection.each, Backbone collections have various Underscore methods mixed in so you don't have to access collection.models manually; I've also switched to this.$el since view already have a cached jQuery'd version of this.el.

Upvotes: 0

Ben_hawk
Ben_hawk

Reputation: 2486

Just found the views el tag corresponded to a bunch of empty <div>s. Not to sure why but a simple el: $('#content') managed to fix the problem. Thanks

Upvotes: 0

bvulaj
bvulaj

Reputation: 5133

Without seeing the corresponding HTML, my best guess is that your <button> is outside the scope of your view. Click events are only attached to children of the root element of your View.

Upvotes: 1

Related Questions