Best solution for inter-component communication?


#1

So I’ve looked around at some previous conversations, but can’t seem to find a definitive answer. If controllers are eventually going away, and actions don’t bubble up through components, how should my components talk to each other?

In Backbone world, I would just use pub/sub, but it’s my understanding this isn’t the best convention here.

For example, say I have a common toolbar component which is populated with different buttons depending on the route. What’s the proper way to inform other components when the user clicks a toolbar item?

EDIT: Another example: Hovering over an item updates a fixed status bar with description text. I imagine an event system for something like this is the best way to go, but just want to make sure I’m not outright missing any glaring conventions to follow doing things the Ember way.


#2

I feel that it would violate some responsibility principle for components to be aware of each other. Maybe sendAction should be used to send it back to the router to change the data that the status bar is showing to the user. That way, if the component is used in any other app (in theory), the router can freely ignore that action if it is not relevant. Also the other component, (ie. the status bar) can choose not to reflect that particular value… if the status bar is used for something else in a different app.


#3

I am totally new to Ember (and pretty much javascript), but I think this is an example of a use condition I was asking about here . My take would be your toolbar for example would define a delegate interface, and when you instantiate the toolbar, you pass a reference to the delegate (it might just be the parent component) then the delegate would communicate with the other components that need to know about toolbar events. This way the toolbar is completely independent and re-usable, he just needs a delegate. As I said I am really new here so hopefully this is not totally off base.


#4

Thanks for chiming in. Finally getting back to this, but here’s how I solved it with more of a DDAU approach, using a global UI service (no pub/sub, and components are not aware of each other).

{{!-- toolbar.hbs --}}
{{#my-button active=ui.isFeatureActive onClick=(action "toggleFeature" target=ui)}}
Button Contents
{{/my-button}}
{{!-- route.hbs --}}
{{#if ui.isFeatureActive}}
 {{feature-component}}
{{/if}}
//services/ui.js
export default Ember.Service.extend({

  isFeatureActive: false,

  actions: {

    toggleFeature() {
      this.set('isFeatureActive', ! this.get('isFeatureActive') );
    }

  }

});
//initializers/ui.js
export function initialize(app) {
  app.inject('controller', 'ui', 'service:ui');
}

export default {
  name: 'ui',
  initialize
};

My button component does a bit more with onClick, but the key is that it’s sending the toggleFeature action directly to the ui service, which is directly accessible anywhere because it’s being injected into all controllers.