HOWTO: Access an Action which is defined in another Controller

From @angus post in Mattermost chat a few days ago:

To access an Ember closure action defined on another controller, you can use getOwner

import { getOwner } from 'discourse-common/lib/get-owner';

export default {
  setupComponent(attrs, component) {
    const controller = getOwner(this).lookup('controller:topic');
  },
}

Once you have the controller you can use controller.send('action')

I can confirm this worked great. I reformatted the code a little, as per my example below:

import { getOwner } from 'discourse-common/lib/get-owner';

export default {
  actions: {
    convertPrivateStoryToPublicStory() {
      const controller = getOwner(this).lookup('controller:topic');
      controller.send('convertToPublicTopic')
    },
    convertPublicStoryToPrivateStory() {
      const controller = getOwner(this).lookup('controller:topic');
      controller.send('convertToPrivateMessage')
    },
  },
};
2 Likes

Some brief notes.

  1. You can store the controller in a computed property on setup to DRY up the code.

  2. Be aware that looking up a controller in the container is basically a “fallback” method, to workaround the fact that in the plugin you’re limited to the plugin-specific contexts (e.g. the attributes passed to a plugin outlet). If there is a way to access the same actions or properties without looking up the class this way, it’s always better to do that.

1 Like

Also, an unrelated note about plugin template connectors. In most instances you should be including a shouldRender callback that uses your plugin_enabled site setting. This will prevent the markup being inserted when your plugin is disabled.

Example:

export default {
  shouldRender(_, ctx) {
    return ctx.siteSettings.plugin_enabled;
  }
}
1 Like