Question

I have decoupled views that I want to respond to each other's events. I added an event aggregator in my application.js file and triggered the event from my function in the first view. I can't seem to get the second view to respond to that event, though. I've looked at Derrick Bailey's discussion of event aggregators and the documentcloud.github.io discussion. I haven't been able to find syntax that works with coffeescript and I'm not sure how to translate the syntax I have found.

My first view that I want to publish the event looks like this:

class Mlp.Views.PoniesIndex extends Backbone.View

  poniesTemplate: JST['ponies/index']

  events:
    'submit #new_pony': 'createPony'
    'click #pony_up': 'ponyUp'

  initialize: ->
    console.log(Mlp.Collections.Settings)
    @collection.on('reset', @render, this)
    @collection.on('add', @appendPony, this)
    @collection.on('change', @render, this)

  ponyUp: (event) ->
    event.preventDefault()
    Mlp.vent.trigger('ponyUp', @collection)
    @collection.ponyDown()
    @collection.ponyUp()

My event aggregator is in the application.js file:

//= require jquery
//= require jquery_ujs
//= require underscore
//= require backbone
//= require mlp
//= require_tree ../templates
//= require_tree ./models
//= require_tree ./collections
//= require_tree ./views
//= require_tree ./routers
//= require_tree .

Mlp.vent = _.extend({}, Backbone.Events);

When I add this to my application.js file I get the console log I want:

Mlp.vent.bind("ponyUp", function(collection){
 console.log("pony up!");
});

But when I try to add an event binder in the view I want to receive the published event I get nothing:

class Mlp.Views.SettingsIndex extends Backbone.View

  template: JST['settings/index']

  events:
     'submit #new_setting': 'createSetting'
     'click #change_of_venue': 'randomSetting'

  initialize: ->
    @collection.on('ponyUp', @alterbox, this) 
    @collection.on('reset', @render, this)
    @collection.on('add', @appendSetting, this)
    @collection.on('change', @render, this)

  alertbox: (collection) ->
    event.preventDefault()
    console.log("pony up!")

I have tried a variety of diffent syntaxes but i'm still not sure whether I should be binding to the collection in the intialization or binding in the events declarations. The examples I've seen use underscore's _.bindAll. When I tried that it threw "cannot read 'bind' of undefined", even though i'm requiring underscore in my application.js. I'm sure this is some basic syntax that I don't understand.

Thank you in advance for any help!

Was it helpful?

Solution

Your collection won't send out a 'ponyUp' event, your event aggregator (Mlp.vent) will. When you say this:

Mlp.vent.trigger('ponyUp', @collection)

You're asking Mlp.vent to send out a 'ponyUp' event with @collection as the argument, you're not triggering a 'ponyUp' event from @collection. That means that you'd want to listen to Mlp.vent for the event and this:

@collection.on('ponyUp', @alterbox, this) 

should look more like this:

Mlp.vent.on('ponyUp', @alterbox, this)

Alternatively, you could trigger the event on the collection by hand with something like this:

@collection.trigger('ponyUp', @collection)

The main difference between the two approaches is that using Mlp.vent allows anyone to listen for the event even if they don't have the collection in hand whereas the @collection.trigger approach requires everyone to have a reference to the collection before they can listen for the event.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top