Search code examples
javascriptember.jsember-cliember-addon

Inject controller actions from within Ember Addon


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);

    };
  }
};

Solution

  • 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.