简体   繁体   中英

How do I aggregate event data using pubsub with backbone.js?

I am building a small booking calculator with backbone.js which mostly responds to user inputs based on manipulating static sets of data. I have the application carved up into separate components like:

  1. Packages
  2. Calendar
  3. Ticket
  4. TotalCostView

The last component TotalCostView is the most important. It outputs the final cost of the booking based on event data published by the other components mentioned in the above list. Now I am using a simple jQuery pub sub implementation as my global eventbus:

  /* jQuery Tiny Pub/Sub - v0.7 - 10/27/2011
 * http://benalman.com/
 * Copyright (c) 2011 "Cowboy" Ben Alman; Licensed MIT, GPL */

  var o = $({});

  $.subscribe = function() {
    o.on.apply(o, arguments);
  };

  $.unsubscribe = function() {
    o.off.apply(o, arguments);
  };

  $.publish = function() {
    o.trigger.apply(o, arguments);
  };

This works pretty well expect for one thing: I cannot access the aggregated data I need to calculate the final totalCost .

So when I publish an event like so:

var SelectListView = Backbone.View.extend({

  events: {
      'change': 'pkgSelected'
  },

  pkgSelected: function(ev){
     $.publish('pkg/changed', selectedPkg);
  },

});

I subscribe to it like so:

$.subscribe('pkg/changed', _.bind(this.updatePackageAmount, this));

I get the current selected package data. The problem is that I am unable to get the data that other parts of the application are publishing like:

$.publish('car/selected', selectedCar);
$.publish('numTickets/changed', ticketData);

I am unable to aggregate all the data in one place for calculation like:

  updatePackageAmount: function(ev, numTickets, travelCost, currentDate){ // I need the data passed in as parameters to be always fresh

    var totalCost = parseInt(cost * numTickets, 10) + parseInt(travelCost, 10);
    this.render(totalCost);
  }, 

How do I aggregate data without one component having knowledge of another component? Should I use some kind of sensible global App object on which to store this common shared data? If so, how would I do this?

Since Backbone v0.9.9, the global Backbone.Events object has had the Backbone events behavior mixed in, so you can use that object as your global event bus. It's a pretty common pattern to have some kind of global event bus to tie all your behavior together. Without one, I think you're left with creating an ownership hierarchy of some kind where higher-level objects bubble up events from their children and trigger events from higher levels on their children.

I think the event bus approach might be easier to deal with in a small application:

var SelectListView = Backbone.View.extend({

  events: {
      'change': 'pkgSelected'
  },

  pkgSelected: function(ev){
     // : is commonly used for event namespacing in Backbone, but feel
     // free to keep using /
     Backbone.Events.trigger('pkg:change', selectedPkg);
  },

});

// Your total view
var SomeOtherView = Backbone.View.Extend({
    initialize: function() {
        var _this = this;
        // If you use listenTo, the event listener will automatically be
        // disabled when your view is removed
        this.listenTo(Backbone.Events, 'pkg:change', function(selectedPkg) {
            _this.selectedPkg = selectedPkg;
        });
    }
)};

You could even use a Backbone.Model for storing the results of all your options: your controller could listen for changes on Backbone.Event , set the appropriate fields on the model itself, and your view could then listen for change events on the model and re-render itself as appropriate.

Anyway, Backbone.Marionette provides a suitable global application object ( Marionette.Application ) which might work for your case (in addition to a lot of other really nice components for building Backbone apps).

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