简体   繁体   中英

How to handle event bubbling?

I am working on a small backbone application.

I currently got the problem that I want to show a profile of a specific item.

This showProfile event is triggered when I click on list item. Not the showProfile event needs to inform the parent listView which informs the above sidebarView which informs the mainView which now can instance the profileView.

This would involve three to four views in the event chain. Is there a possible workaround for this problem?

Regards, Bodo

I don't know if it's the best way, but for this kind of scenario, I've used an application-level event aggregator by creating an object which has an event property that extends Backbone.Events.

I tend to use the same object for storing application-wide settings as well:

var app = {
    settings: {},
    events: _.extend({}, Backbone.Events),
};

You can then trigger a showProfile event from your view and bind to app.event in your mainView, without bubbling through all the parent views.

When using RequireJS, I create an app module, which is a dependency for my views:

define([
    "jquery",
    "underscore",
    "backbone"
],

function($, _, Backbone) {
   var app = {
       root: "/",
       settings: {},
       events: _.extend({}, Backbone.Events),
   };

 return app;

});

I also tend to place my router on the app object in case I need to access it in a view, so in my main.js (like in backbone-boilerplate ):

require([
   "app",
   "router",
],

function(app, Router) {
    app.router = new Router();
    Backbone.history.start({ pushState: true, root: app.root });
});

You might want to read Derick Bailey's blog posts about event aggregators:

http://lostechies.com/derickbailey/2011/07/19/references-routing-and-the-event-aggregator-coordinating-views-in-backbone-js/

http://lostechies.com/derickbailey/2012/04/03/revisiting-the-backbone-event-aggregator-lessons-learned/

Agreed, there's a lot of boilerplate involved in this sort of thing. One approach I've tried is minimising this by using a (view) method such as the one defined below:

/**
 * Helper to facilitate event-bubbling, that is to say, the scenario where a view
 * binds a callback to a child-View event only to retrigger it, mimicking the
 * inherent event bubbling mechanism of the DOM. Allows renaming of the bubbled
 * event as well as modification of the bubbled arguments
 *
 * @param view The View-dispatcher of the event
 * @param ev Name of the event to bubble
 * @param opts A hash of options where:
 *   bubbleName: New name of the event to bubble in case the event should be
 *   renamed. Optional
 *   args: The arguments to bubble:
 *    - When absent, the original arguments will be bubbled.
 *    - When set to a non-function value or an array-of-values, this value or
 *      values will be bubbled
 *    - When set to a function, it will be invoked on the incoming arguments and
 *      its returned value will be treated as in the previous case.
 */
bubbleEvent: function (view, ev, opts) {
  if (!opts) { opts = {}; }
  view.bind(ev, function () {
    var inArgs = _.toArray(arguments),
        bubbleArgs = _.isFunction(opts.args) ? 
          opts.args.apply(this, inArgs) : (opts.args || inArgs),
        bubbleName = opts.bubbleName || ev;
    this.trigger.apply(this, [bubbleName].concat(bubbleArgs));
  }, this);
}

This would be a member function of a BaseView which all your other Views would extend. So it would be available in every view of the app. So in order for a ParentView to simply bubble an event triggered by an owned childView you would only need

bubbleEvent(childView, "event");

Still, this introduces some boilerplate so I too would be interested in seeing other solutions to this problem.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM