Overwrite event hash for inherited Backbone.js View

I have a Backbone View for a common element from which certain elements are inherited. I have an event handling logic that should apply to all elements, and an event processing logic specific to elements of a child type. I am having problems because the child view has its own callback for the event, which is also handled by the parent view, and therefore when I try to use hash events in both cases, either the child callback or the parent call is never called. Let me illustrate with some code:

var ElementView = Backbone.View.extend({ events: { "mouseup": "upHandler", "mousedown": "downHandler", "mousemove": "moveHandler" }, initialize: function() { // add events from child if (this.events) this.events = _.defaults(this.events, ElementView.prototype.events); this.delegateEvents(this.events); } }); var StrokeView = ElementView.extend({ events: { "mousemove": "strokeMoveHandler" } }); 

How can I solve this in an extensible way, especially if I later have a different level of inheritance?

+4
source share
2 answers

One way to handle this is to use namespaces for events:

 var ElementView = Backbone.View.extend({ events: { "mouseup.element": "upHandler", "mousedown.element": "downHandler", "mousemove.element": "moveHandler" }, initialize: function() { // add events from child if (this.events) this.events = _.defaults(this.events, ElementView.prototype.events); this.delegateEvents(this.events); } }); var StrokeView = ElementView.extend({ events: { "mousemove.strokeview": "strokeMoveHandler" } }); 

In fact, this approach is suggested in the Backbone.js documentation .

+8
source

I did something similar using faux- super JavaScript, as mentioned in the Backbone.js documentation , and the initialization function

 var ElementView = Backbone.View.extend({ events: { "mouseup": "upHandler", "mousedown": "downHandler", "mousemove": "moveHandler" }, initialize: function() { this.delegateEvents(); } }); var StrokeView = ElementView.extend({ initialize: function() { this.events = _.extend({}, this.events, { "mousemove": "strokeMoveHandler" }); // Call the parent initialization function ElementView.prototype.initialize.call(this); } }); var SubStrokeView = StrokeView.extend({ initialize: function() { this.events = _.extend({}, this.events, { "click": "subStrokeClickHandler", "mouseup": "subStrokeMouseupHandler" }); // Call the parent initialization function StrokeView.prototype.initialize.call(this); } }); var c = new SubStrokeView(); console.log(c.events); // Should be something like // click: "subStrokeClickHandler" // mousedown: "downHandler" // mousemove: "strokeMoveHandler" // mouseup: "subStrokeMouseupHandler" 

The magic happens by setting events in the initialize function. If your prototypes have several events attributes, JavaScript will only see the one that was installed most recently due to how prototyping works.

Instead, doing it this way, each view sets its own this.events , then calls its parent function initialize , which in turn extends this.events with its events, etc.

You need to install this.events as follows:

 this.events = _.extend({}, this.events, ...new events...); 

instead

 _.extend(this.events, ...new events...); 

Performing this second method will create an event object in the parent ( ElementView ) prototype. The first method ensures that each model gets its own copy.

+4
source

Source: https://habr.com/ru/post/1393078/


All Articles