1

Lets say I have a standalone addon with a playback component:

{{my-record play="recordPlay" stop="recordStop"}}

/app/components/my-record.js

import Ember from 'ember';

export default Ember.Component.extend({
  actions: {
    play: function() {
      this.sendAction('play');
    },
    stop: function() {
      this.sendAction('stop');
    }
  }
});

I want the addon to work independently with backend and handle all actions internally. How do I handle these two actions recordPlay and recordStop from within the addon itself so that I don't need to touch controller/routes of the consuming application?

I have tried:

  • creating application controller within the addon eg. `/app/controllers/application.js - this is never called

  • creating application route within the addon eg. `/app/routes/application.js - this is called unless consuming application has it's own ApplicationRoute which overrides the addon's route

Can I use initializers somehow from within the addon to inject these two actions to ApplicationController?

EDIT: Dirty workaround using ApplicationRoute._actions

/app/initializers/record.js

export default {
  name: 'record',

  initialize: function(container, app) {

    var applicationRoute = container.lookup('route:application');

    applicationRoute._actions.recordPlay = function(id) {

        console.log('CALLED recordPlay', id);
    };

    applicationRoute._actions.recordStop = function(id) {

        console.log('CALLED recordStop', id);

    };
  }
};
WooDzu
  • 4,771
  • 6
  • 31
  • 61
  • Why would you want to force the implementation on the index controller and not just handle it in the component? The index controller/route is only used when you're at the root of the application. – Kingpin2k Oct 06 '14 at 15:29
  • Thanks for looking into this @Kingpin2k. To my knowledge component should not be aware of outside word - thus should not interact with store, ember data, APIs etc.. or am I missing some concept here? – WooDzu Oct 06 '14 at 15:41
  • The idea behind injecting actions into ApplicationController is that a triggered action would bobble up the route tree from whatever is the current route. But still allows routes/resources to catch it mid-way through if needed – WooDzu Oct 06 '14 at 15:57

1 Answers1

0

It seems you are struggling to fulfill constraints that are almost contradictory -- this forces you into a solution that is probably worse than violating your constraints.

The constraints are: (1) component unaware of outside world, but (2) add-on as a whole interacts with the back-end autonomously.

Then your component signals it wants something done, and you want your add-on to provide a default way of doing things.

The idea of components unaware of the outside world is that then they can be used in different contexts. Is it realistic to use your component outside your addon? It seems like you want the "default way of doing things" to be baked in.

One way you could compromise is to use a blueprint to inject an adaptor into your component. The adaptor would then interact with the store (etc?). However, if a consumer wanted to do things differently, they could not define the adaptor and define actions instead, or use a different adaptor.

shaunc
  • 5,317
  • 4
  • 43
  • 58
  • Interesting idea, I'm not sure how to I approach it though. Is there an example you could reference to? Thanks – WooDzu Jan 20 '15 at 19:35
  • Haven't actually tried it -- and am in middle of sprint, so don't have time to experiment. However, idea is that component checks for `this.recorderAdaptor` -- if found, then tells it do what it needs to. Otherwise (or in addition), it calls `sendAction( ... )`. If you don't want automatic config, then instead of injecting recorderAdaptor, you could just have "recorderAdaptor" be a property configurable by template. (Indeed, you could just have callbacks e.g. "recordPlayCallback".) A bit inelegant, but now "recorderAdaptor", switchable globally w/ injection or locally by overriding. – shaunc Jan 22 '15 at 07:46