admin管理员组

文章数量:1287990

I have a Backbone View for a general element that specific elements will be inheriting from. I have event handling logic that needs to be applied to all elements, and event handling logic that is specific to child-type elements. I'm having trouble because a child View has its own callback for an event that is also handled by the parent View, and so when I try to use the events hash in both, either the child or parent callback 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 would I solve this in an extensible way, especially if I will later have another level of inheritance?

I have a Backbone View for a general element that specific elements will be inheriting from. I have event handling logic that needs to be applied to all elements, and event handling logic that is specific to child-type elements. I'm having trouble because a child View has its own callback for an event that is also handled by the parent View, and so when I try to use the events hash in both, either the child or parent callback 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 would I solve this in an extensible way, especially if I will later have another level of inheritance?

Share Improve this question asked Jan 26, 2012 at 1:15 troyastorinotroyastorino 2354 silver badges13 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 8

One way to handle this would be 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 Backbone.js documentation.

I've done something similiar by taking advantage of JavaScript's faux-super 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's 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's 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 the events within the initialize function. If you have multiple events attributes in your prototypes, JavaScript will only see the one set most recently due to how prototyping works.

Instead, by doing it this way, each view sets its own this.events, then calls its parent's initialize function which in turn extends this.events with its events, and so on.

You do need to set this.events in this specific way:

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

instead of

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

Doing it the second way will munge the events object within the parent's (ElementView) prototype. The first way ensures each model gets its own copy.

本文标签: javascriptOverwriting events hash for inherited Backbonejs ViewStack Overflow