0
votes

I have a view in Backbone with a number of subviews. The subview's events aren't firing, and I'm having trouble understanding why. I've been following a tutorial that shows how to get a subview's event to fire:

https://ianstormtaylor.com/rendering-views-in-backbonejs-isnt-always-simple

The following is a relevant portion of code:

var TaskView = Backbone.View.extend({
    tagName: "div",
    template: _.template($("#taskAddTemplate").html()),
    render: function () {
        // append the template to the element
        this.$el.append(this.template);

        var scheduleData = new ScheduleModel(this.model.attributes.Schedule);
        this.Schedule = new ScheduleView({ model: scheduleData });
        this.assign(this.Schedule, "#ScheduleDetails");
        return this;
    },
    assign: function(view, selector) {
        view.setElement(this.$(selector)).render();
    },
    events: {
        "submit #NewTaskForm": function (e) {
            e.preventDefault();

            $("#SaveTaskButton").effect("pulsate", { times: 0 }, 0);
            console.log("In submit for task");
        }
    }

});

var ScheduleView = Backbone.View.extend({
    tagName: "div",
    template: _.template($("#scheduleAddTemplate").html()),
    render: function () {
        // append the template to the element
        this.$el.append(this.template(this.model.toJSON()));
        // set the schedule type
        var renderedInterval = SetScheduleType(this.model);
        // append to the interval
        $("#Interval", this.$el).append(renderedInterval.el);
        return this;
    },
    events: {
        "submit #NewTaskForm": function (e) {
            e.preventDefault();
            console.log("In submit for schedule");
        }
    }
});

The views appear correctly, but whenever I click the submit button with the id NewTaskForm the event is fired for the Task view, but not the Schedule view. What am I doing wrong?

EDIT:

The following are the templates:

<script id="taskAddTemplate" type="text/html">
    <nav class="navbar navbar-default" id="TaskMenu">
        <ul class="nav navbar-nav" id="TaskTabs">
            <li role="presentation"><a href="#TaskDetails" aria-controls="Task Details" role="tab" data-toggle="tab">Task Details</a></li>
            <li role="presentation"><a href="#ScheduleDetails" aria-controls="Schedule Details" role="tab" data-toggle="tab">Schedule Details</a></li>
        </ul>
    </nav>

    <form class="form form-horizontal" id="NewTaskForm">
        <div class="tab-content">

            <div role="tabpanel" class="tab-pane" id="TaskDetails">
                <div class="form-group">
                    <label class="col-xs-2 control-label">Task Name: </label>
                    <input class="col-xs-10 form-control" type="text" id="TaskName" name="TaskName" />

                </div>
                <div class="form-group">
                    <label class="col-xs-2 control-label">Message: </label>
                    <textarea class="col-xs-10 form-control" rows="5" type="text" id="Message" name="Message"></textarea>
                </div>
            </div>

            <div role="tabpanel" class="tab-pane" id="ScheduleDetails"></div>

            <div class="form-group">
                <div class="container">
                    <div class="col-xs-2">
                        <input type="submit" class="form-control btn btn-primary col-xs-2" id="SaveTaskButton" />
                    </div>
                    <div class="col-xs-2">
                        <input type="button" class="form-control btn btn-danger col-xs-2" id="CancelNewTaskButton" value="Cancel" />
                    </div>
                </div>
            </div>
        </div>
    </form>
</script>


<script id="scheduleAddTemplate" type="text/html">
    <div id="Schedule" class="form-group">

        <div class="row">
            <div class="col-xs-3">
                <span class="col-xs-1"></span>
                <select class="form-control" id="ScheduleType" data-val="true" data-val-required="The Schedule Type Field is require.">
                    <option value="hourly">Hourly</option>
                    <option value="daily">Daily</option>
                    <option value="weekly">Weekly</option>
                    <option value="monthly">Monthly</option>
                </select>
            </div>
            <div id="Interval" class="col-xs-9"></div>

        </div>

        <div id="StartAndEnd" class="row">

            <label class="control-label col-xs-1">Start</label>
            <input type="text" class="date form-control col-xs-2" id="StartDate" value="<%= StartDate %>" />
            <input type="text" class="time form-control col-xs-1" id="StartTime" value="<%= StartTime %>" />
            <label class="control-label col-xs-1">End</label>
            <input type="text" class="date form-control col-xs-1" id="EndDate" value="<%= EndDate %>" />
            <span class="col-xs-2"></span>
        </div>
    </div>
</script>
1
Do both templates (taskAddTemplate and scheduleAddTemplate) have the #NewTaskForm defined into their bodies?zon7
No, the taskAddTemplate is the "master view" that has a form which takes values from the scheduleAddTemplateMichelle
Ok. The problem is that the event tag in Backbone affects only the inner html, that way you can have multiple children with events to same tag. In your case, if you want the event to be trigger in both views, you will have to pass an event or change your structurezon7
Ok, so is there a way to get the Schedule View to take care of saving it's model when the Task View's save button is pushed?Michelle
Yes, it's easy done. Can you post your templates html so i can write the correct answer?zon7

1 Answers

2
votes

Ok, there are two ways:

First way

The easy way will be to move the NewTaskForm to the scheduleAddTemplate. That way, the event will be triggered there, and then you can fire it up with trigger

events: {
    "submit #NewTaskForm": 'onSubmit'
},
onSubmit: function(ev){
    e.preventDefault();
    console.log("In submit for schedule");
    //TODO: Call the save method
    this.model.save(
        success: function(...){
            this.trigger('save')
        }
    )
}

and in the TaskView add this in the render method

var scheduleData = new ScheduleModel(this.model.attributes.Schedule);
this.Schedule = new ScheduleView({ model: scheduleData });
this.assign(this.Schedule, "#ScheduleDetails");
this.listenTo(this.Schedule, "save", function(...){})

Second way

The other way around will be to call a method from TaskView to ScheduleView. As you already have a variable storing the view you can just call do it in your event method

events: {
    "submit #NewTaskForm": function (e) {
        e.preventDefault();

        $("#SaveTaskButton").effect("pulsate", { times: 0 }, 0);
        console.log("In submit for task");
        this.Schedule.method_name()
    }
}

Anyway, as you have no extra logic in the schedule view, there is no need for the extra view and you can do everything in one simple view.