Backbone events not firing & general feedback on use of the framework

Go To StackoverFlow.com

2

I am very new to backbone.js and I am struggling a little. I figured out a way to get data from the server (in json) onto the screen successfully but am I doing it the right/best way?

All my view have this.el set but the events of the views are not firing ()... What is the best way forward?

Here is the code:

var surveyUrl = "/api/Survey?format=json&callback=?";

AnswerOption = Backbone.Model.extend({});

AnswerOptionView = Backbone.View.extend({

    initialize: function () {
        _.bindAll(this, 'updateCheckedState');
    },

    events: {
        "click .answerOptionControl": "updateCheckedState" //still noy firing :-(
    },

    render: function() {
        this.model.get('answerOption').questionChoiceType = this.model.get('questionChoiceType');
        var template = _.template($("#questionAnswerOptionTemplate").html(), this.model.get('answerOption'));

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

    updateCheckedState: function(e) {
        alert("Here is my event origin: " + e.target)
    }
});

Question = Backbone.Model.extend({});

QuestionView = Backbone.View.extend({
    render: function() {

        var template = _.template($("#questionTemplate").html(), this.model.get('question'));
        $(this.el).html(template);

        /*validator code removed*/

        for (var i = 0; i < this.model.get('question').answerOptions.length; i++) {
            var qModel = new AnswerOption({
                answerOption: this.model.get('question').answerOptions[i]
            });

            var view = new AnswerOptionView({ model: qModel });

            this.$('fieldset').append(view.render().el.innerHTML);
        }

        return this;
    }
});

Survey = Backbone.Model.extend({
    url: function () { return this.get("id") ? surveyUrl + '/' + this.get("id") : surveyUrl; }
});

SurveyList = Backbone.Collection.extend({
    model: Survey,
    url: surveyUrl
});

SurveyView = Backbone.View.extend({
    initialize: function () {
        _.bindAll(this, 'render');
        this.model.bind('refresh', this.render);
        this.model.bind('change', this.render);
    },

    // Re-render the contents
    render: function () {
        for (var i = 0; i < this.model.attributes[0].questions.length; i++) {

            var view = new QuestionView();
            var qModel = new Question({
                question: this.model.attributes[0].questions[i]
            });

            view.model = qModel;
            $(this.el).append(view.render().el.innerHTML);
        }

        this.el.trigger('create');
    }
});

$(document).ready(
function () {
    aSurvey = new Survey({ Id: 1 });
    window.App = new SurveyView({ model: aSurvey, el: $("#questions") });
    aSurvey.fetch();
});

-html

<body>
    <div id="questions"></div>
    <!-- Templates -->
    <script type="text/template" id="questionAnswerOptionTemplate">
        <input name="answerOptionGroup<%= questionId %>" id="answerOptionInput<%= id %>" type="checkbox" class="answerOptionControl"/> 
        <label for="answerOptionInput<%= id %>"><%= text %></label> 
    </script>
    <script type="text/template" id="questionTemplate">
        <div id="question<%=id %>" class="questionWithCurve">
            <h1><%= headerText %></h1>
            <h2><%= subText %></h2>
            <div data-role="fieldcontain" id="answerOptions<%= id %>" >
                <fieldset data-role="controlgroup" data-type="vertical">
                    <legend> </legend>
                </fieldset>
            </div>
        </div>
    </script>
</body>

And the JSON from the server:

? ({
    "name": "Survey",
    "questions": [{
        "surveyId": 1,
        "headerText": "Question 1",
        "subText": "subtext",
        "type": "Choice",
        "positionOrder": 1,
        "answerOptions": [{
            "questionId": 1,
            "text": "Question 1 - Option 1",
            "positionOrder": 1,
            "id": 1,
            "createdOn": "\/Date(1333666034297+0100)\/"
        }, {
            "questionId": 1,
            "text": "Question 1 - Option 2",
            "positionOrder": 2,
            "id": 2,
            "createdOn": "\/Date(1333666034340+0100)\/"
        }, {
            "questionId": 1,
            "text": "Question 1 - Option 3",
            "positionOrder": 3,
            "id": 3,
            "createdOn": "\/Date(1333666034350+0100)\/"
        }],
        "questionValidators": [{
            "questionId": 1,
            "value": "3",
            "type": "MaxAnswers",
            "id": 1,
            "createdOn": "\/Date(1333666034267+0100)\/"
        }, {
            "questionId": 1,
            "value": "1",
            "type": "MinAnswers",
            "id": 2,
            "createdOn": "\/Date(1333666034283+0100)\/"
        }],
        "id": 1,
        "createdOn": "\/Date(1333666034257+0100)\/"
    }, {
        "surveyId": 1,
        "headerText": "Question 2",
        "subText": "subtext",
        "type": "Choice",
        "positionOrder": 2,
        "answerOptions": [{
            "questionId": 2,
            "text": "Question 2 - Option 1",
            "positionOrder": 1,
            "id": 4,
            "createdOn": "\/Date(1333666034427+0100)\/"
        }, {
            "questionId": 2,
            "text": "Question 2 - Option 2",
            "positionOrder": 2,
            "id": 5,
            "createdOn": "\/Date(1333666034440+0100)\/"
        }, {
            "questionId": 2,
            "text": "Question 2 - Option 3",
            "positionOrder": 3,
            "id": 6,
            "createdOn": "\/Date(1333666034447+0100)\/"
        }],
        "questionValidators": [{
            "questionId": 2,
            "value": "3",
            "type": "MaxAnswers",
            "id": 3,
            "createdOn": "\/Date(1333666034407+0100)\/"
        }, {
            "questionId": 2,
            "value": "1",
            "type": "MinAnswers",
            "id": 4,
            "createdOn": "\/Date(1333666034417+0100)\/"
        }],
        "id": 2,
        "createdOn": "\/Date(1333666034377+0100)\/"
    }, {
        "surveyId": 1,
        "headerText": "Question 3",
        "subText": "subtext",
        "type": "Choice",
        "positionOrder": 3,
        "answerOptions": [{
            "questionId": 3,
            "text": "Question 3 - Option 1",
            "positionOrder": 1,
            "id": 7,
            "createdOn": "\/Date(1333666034477+0100)\/"
        }, {
            "questionId": 3,
            "text": "Question 3 - Option 2",
            "positionOrder": 2,
            "id": 8,
            "createdOn": "\/Date(1333666034483+0100)\/"
        }, {
            "questionId": 3,
            "text": "Question 3 - Option 3",
            "positionOrder": 3,
            "id": 9,
            "createdOn": "\/Date(1333666034487+0100)\/"
        }],
        "questionValidators": [{
            "questionId": 3,
            "value": "3",
            "type": "MaxAnswers",
            "id": 5,
            "createdOn": "\/Date(1333666034463+0100)\/"
        }, {
            "questionId": 3,
            "value": "1",
            "type": "MinAnswers",
            "id": 6,
            "createdOn": "\/Date(1333666034470+0100)\/"
        }],
        "id": 3,
        "createdOn": "\/Date(1333666034457+0100)\/"
    }, {
        "surveyId": 1,
        "headerText": "Question 4",
        "subText": "subtext",
        "type": "Choice",
        "positionOrder": 4,
        "answerOptions": [{
            "questionId": 4,
            "text": "Question 4 - Option 1",
            "positionOrder": 1,
            "id": 10,
            "createdOn": "\/Date(1333666034500+0100)\/"
        }, {
            "questionId": 4,
            "text": "Question 4 - Option 2",
            "positionOrder": 2,
            "id": 11,
            "createdOn": "\/Date(1333666034507+0100)\/"
        }, {
            "questionId": 4,
            "text": "Question 4 - Option 3",
            "positionOrder": 3,
            "id": 12,
            "createdOn": "\/Date(1333666034507+0100)\/"
        }],
        "questionValidators": [{
            "questionId": 4,
            "value": "3",
            "type": "MaxAnswers",
            "id": 7,
            "createdOn": "\/Date(1333666034493+0100)\/"
        }, {
            "questionId": 4,
            "value": "1",
            "type": "MinAnswers",
            "id": 8,
            "createdOn": "\/Date(1333666034497+0100)\/"
        }],
        "id": 4,
        "createdOn": "\/Date(1333666034490+0100)\/"
    }],
    "id": 1,
    "createdOn": "\/Date(1333666034243+0100)\/"
})
2012-04-05 23:13
by Leonardo Seccia
While I don't have time at the moment to look through your code, you might find this article helpful. I believe the author is a regular contributor on StackOverflow, too - Colin Brock 2012-04-05 23:31
Hi Colin, thanks for the link. Excellent article. I changed and simplified the code but I still have the event problem.. - Leonardo Seccia 2012-04-06 15:45


1

It doesn't work because of how you append the subview

this.$('fieldset').append(view.render().el.innerHTML);

The way the events handling works in Backbone.Views is that events rather then being attached to elements are attached to the root element of the view and then they are delegated to the children elements. In your case instead of appending the root element of the subview to the parent view you append its contents breaking the event handling as the element to which you bind events never makes it to the DOM.

this.$('fieldset').append(view.render().el);

remove the innerHTML property and it will work again. If you dont want to have wrapping element when instantiating Backbone.Views you can always pass element to be claimed as el options property.

var view = new AnswerOptionView({ model: qModel, el: this.$('fieldset') }).render();

this way the AnswerOptinView will claim the fieldset element and will bind the events to it.

2012-04-07 08:26
by Tom Tu
Ads