I have two views -- a layout view, which is top-level, and a new form view, which acts as a child to the layout and renders within it. I have one event handler in the form view, which is supposed to create a new instance of my model according to the data from the input.
Here's the layout view:
var LayoutView = Backbone.View.extend({
el: "#layout",
render: function (view) {
this.child = view;
if (this.child) {
this.child.remove();
}
this.$el.html(this.child.render().el);
return this;
}
});
and here's my form view:
var ResumeForm = Backbone.View.extend({
events: {
'click #create': 'createResume'
},
initialize: function () {
this.template = _.template($('#new-resume').html());
},
render: function () {
this.$el.html(this.template());
return this;
},
createResume: function () {
// getting values from template inputs and saving them to model
var resume = new Resume({
profession: $('#profession').val(),
firstName: $('#firstname').val(),
lastName: $('#lastname').val()
});
// saving a new model to collection instance
resumes.add(resume);
resume.save(null, {
success: function (res) {
console.log("POST resume id " + res.toJSON().id);
},
error: function () {
console.log("Failed to POST");
}
});
}
});
My form view renders within my layout view perfectly, but when I enter the values and click #create
button, nothing happens -- neither saves the model nor logs any error mistake from my createResume
method. I suspect that when rendering a form view in the layout view, the line this.$el.html(this.child.render().el);
just destroys all event listeners, because if I add these listeners to layout view, it works.
Are there any ways to override this problem?
Backbone's view remove
function undelegates the events bound to the el
.
From the annotated source :
remove: function() { this._removeElement(); this.stopListening(); return this; }, _removeElement: function() { this.$el.remove(); },
This has to do with jQuery .remove()
function (emphasis mine):
Similar to
.empty()
, the.remove()
method takes elements out of the DOM. Use.remove()
when you want to remove the element itself, as well as everything inside it. In addition to the elements themselves, all bound events and jQuery data associated with the elements are removed . To remove the elements without removing data and events, use.detach()
instead.
If you call remove
before reusing the view, you need to manually call the this.delegateEvents()
to re-bind the events from the events
hash and re-wire any event the view was listening through this.listenTo(...)
.
But the best way to re-use views, without calling remove
which calls stopListening
, you can use setElement
which undelegates the events, and change the view element to the passed element, then re-delegates the events.
setElement: function(element) { this.undelegateEvents(); this._setElement(element); this.delegateEvents(); return this; },
Your LayoutView
would become something like this:
var LayoutView = Backbone.View.extend({
el: "#layout",
render: function(view) {
// if the view is different, make sure to undelegate the old view.
if (this.child && this.child !== view) this.child.undelegateEvents();
this.child = view;
this.child.setElement(this.$el).render();
return this;
}
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.