Problem:
I'm trying to attach a resize event to the window from a view using the new listenTo() method in Backbone.js. The event seems to bind to the window, however, when the window is actually resied the following error is thrown:
Uncaught TypeError: Object [object Object] has no method 'apply' jquery.js:2 p.event.dispatch jquery.js:2 p.event.add.g.handle.h
Here is the code that attaches the event to the view:
this.listenTo($(window),"resize", this.resizeContext, this));
Here is the resizeContext function:
resizeContext: function(event) {
console.log("resizing context for "+this.id);
this.setHeight();
// trigger resize event (use event bus)
this.options.vent.trigger("resize", event);
}
Note: using the standard $(window).on("resize",this.resizeContext)
attaches the event and runs as it should. I am trying to take advantage of the new stopListening()
feature that is added to view.remove();
The new listenTo
and stopListening
are methods of the Backbone.Events
mixin, and they can only be used to listen to Backbone events which are triggered with .trigger
, such as the built-in collection:add
, or model:change
events.
That means that you won't be able to utilize the stopListening
functionality for DOM events such as window:resize
.
Consider overriding the View.remove
method instead.
var SomeView = Backbone.View.extend({
initialize:function() {
$(window).on("resize",this.resizeContext)
},
remove: function() {
$(window).off("resize",this.resizeContext);
//call the superclass remove method
Backbone.View.prototype.remove.apply(this, arguments);
}
});
If you want to keep using listenTo
you might want to use following one off wrapper for DOM elements:
/**
* Use Backbone Events listenTo/stopListening with any DOM element
*
* @param {DOM Element}
* @return {Backbone Events style object}
**/
function asEvents(el) {
var args;
return {
on: function(event, handler) {
if (args) throw new Error("this is one off wrapper");
el.addEventListener(event, handler, false);
args = [event, handler];
},
off: function() {
el.removeEventListener.apply(el, args);
}
};
}
Example:
view.listenTo(asEvents(window), "resize", handler);
and the listener will be remove automatically on view.remove()
or view.stoplistening()
Here's more complex implementation for multiple event listeners https://gist.github.com/epeli/5927950
In my code, I need to do .debounce((this.resizeContext).bind(this)).
Which makes it harder to be turned off. As a dirty solution, I just turn off all 'resize' listener when remove the view. I guess in the new view, if there is any resize listener, it will be turned on again.
remove: function() {
$(window).off("resize");
//call the superclass remove method
Backbone.View.prototype.remove.apply(this, arguments);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With