# Using a Discourse component in a plugin

**URL:** https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155
**Category:** Development
**Created:** [January 22, 2017, 7:33am UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155 "2017-01-22T07:33:38Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![jgujgu](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jgujgu/32/64012_2.png) [@jgujgu](https://meta.discourse.org/u/jgujgu)
#### Post date: [January 22, 2017, 7:33am UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/1 "2017-01-22T07:33:38Z")

</div>

I have a question about reusing Discourse “core” Ember components in plugins. More particularly, I ran into trouble today trying to put a “signup” d-button into a plugin template.

Here is where I tried to do:

> <https://github.com/jgujgu/discourse-call-to-action/blob/master/assets/javascripts/discourse/templates/connectors/discovery-below/call-to-action.hbs#L14>

And this is the console error it created:

 ![](https://global.discourse-cdn.com/meta/original/3X/2/0/20c435932ef839944c06aa75233f3d6b62ea9564.png)

I understand (very vaguely?) that showCreateAccount is a controller function passed along to different components that need it:

> <https://github.com/discourse/discourse/blob/adb73180f727be5b5bf4772c81f99e5ac9d10eea/app/assets/javascripts/discourse/templates/application.hbs#L3>

Moreover, in order to get this modal to pop up in my component, do I need to fundamentally change the structure of my files? I don’t think my file structure is necessarily correct either. 😓

---

<div class="post-metadata">

### Author: ![joebuhlig](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joebuhlig/32/193054_2.png) [@joebuhlig](https://meta.discourse.org/u/joebuhlig)
#### Post date: [January 22, 2017, 7:48pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/2 "2017-01-22T19:48:36Z")

</div>

I just dropped this into a handlebars template out of curiosity:

```handlebars
{{d-button action="showCreateAccount" class="btn-primary sign-up-button" label="sign_up"}}

```

It worked like a charm. It gave me a “Sign Up” button that displayed the account creation modal. Note that this works when the template is specific to the plugin and not through a connector.

That said, if I do the same thing in a handlebars template that is using a `plugin-outlet` through a connector, it fails. Makes me think the connector templates aren’t inheriting actions from above. @eviltrout, is there any truth to that? That would be good to know. Even templates that have [the action available](https://github.com/discourse/discourse/blob/05e99a68cec550eb3b1aa9703bdca462e74303e7/app/assets/javascripts/discourse/templates/static.hbs) _and_ a `plugin-outlet` fail when the connector is used.

On another note, try inserting `{{signup-cta}}` in your handlebars file. See if that’s something you’re interested in.

---

<div class="post-metadata">

### Author: ![eviltrout](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/eviltrout/32/5275_2.png) [@eviltrout](https://meta.discourse.org/u/eviltrout)
#### Post date: [January 23, 2017, 5:00pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/3 "2017-01-23T17:00:58Z")

</div>

> [@joebuhlig](#):
>
> Makes me think the connector templates aren’t inheriting actions from above.

As of Ember 2.10 we can’t just inherit the exact same context as the parent template, so outlets only have access to things that are explicitly passed into them, including actions.

We’ve tried to pass in all the data an outlet would need, but if you find a case where an action is needed in an outlet and it can’t call it, we can accept a PR to handle htat.

---

<div class="post-metadata">

### Author: ![joebuhlig](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joebuhlig/32/193054_2.png) [@joebuhlig](https://meta.discourse.org/u/joebuhlig)
#### Post date: [January 23, 2017, 6:29pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/4 "2017-01-23T18:29:46Z")

</div>

> [@eviltrout](#):
>
> outlets only have access to things that are explicitly passed into them

Is there a way to augment what’s passed through a plugin? That way we don’t create any extra bloat with PRs to add actions.

---

<div class="post-metadata">

### Author: ![eviltrout](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/eviltrout/32/5275_2.png) [@eviltrout](https://meta.discourse.org/u/eviltrout)
#### Post date: [January 23, 2017, 7:53pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/5 "2017-01-23T19:53:39Z")

</div>

No unfortunately the contract between the parent template and the outlet has to be explicit.

It is a little more limiting, but on the other hand it means we know exactly what objects / actions outlets can be using which helps us not break things in the future.

---

<div class="post-metadata">

### Author: ![joebuhlig](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joebuhlig/32/193054_2.png) [@joebuhlig](https://meta.discourse.org/u/joebuhlig)
#### Post date: [January 25, 2017, 12:47pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/6 "2017-01-25T12:47:53Z")

</div>

> [@eviltrout](#):
>
> the contract between the parent template and the outlet has to be explicit

I spent a little time digging through the Ember pieces of plugin-outlets and came up short. I didn’t see where the actions passed are explicitly defined. Are they passed through the component in `buildArgs`?

---

<div class="post-metadata">

### Author: ![eviltrout](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/eviltrout/32/5275_2.png) [@eviltrout](https://meta.discourse.org/u/eviltrout)
#### Post date: [January 25, 2017, 4:06pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/7 "2017-01-25T16:06:54Z")

</div>

`buildArgs` is only used for our [widgets](https://meta.discourse.org/t/a-tour-of-how-the-widget-virtual-dom-code-in-discourse-works/40347).

I did a quick search through our codebase and I couldn’t find an action being passed in either which is quite interesting, which tells me that most plugins just operate on the objects they are working on!

Having said that, it would look like this:

```hbs
{{plugin-outlet 
  name="some-outlet" 
  args=(hash model=model someAction=(action "someAction"))}}

```

Then in your component you could do `this.attrs.someAction()`

---

<div class="post-metadata">

### Author: ![joebuhlig](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joebuhlig/32/193054_2.png) [@joebuhlig](https://meta.discourse.org/u/joebuhlig)
#### Post date: [January 25, 2017, 4:36pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/8 "2017-01-25T16:36:08Z")

</div>

I tried altering a handful of plugin-outlets and managed to get the same error each time:

`Assertion Failed: No application initializer named 'inject-discourse-objects'`

The outlets don’t like it when I give them an action of any kind. I’m specifically looking at the [`static.hbs` template](https://github.com/discourse/discourse/blob/05e99a68cec550eb3b1aa9703bdca462e74303e7/app/assets/javascripts/discourse/templates/static.hbs) since the action is already called there. That way I know it’s available.

> [@eviltrout](#):
>
> which tells me that most plugins just operate on the objects they are working on!

I can’t say that I can think of an instance where I’ve tried to do this in any way. I’ve always used my own actions. But I could see the benefit of using them in the future. I just can’t think of an example right now.

Edit: Robin! That whole `rm -rf tmp` thing still gets me sometimes. I still get an error but it’s not the same:

`Assertion Failed: <(subclass of Ember.Component):ember1016> had no action handler for: showCreateAccount`

---

<div class="post-metadata">

### Author: ![eviltrout](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/eviltrout/32/5275_2.png) [@eviltrout](https://meta.discourse.org/u/eviltrout)
#### Post date: [January 25, 2017, 8:09pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/9 "2017-01-25T20:09:15Z")

</div>

You are getting that error when calling `this.attrs.showCreateAccount()` after passing it in?

---

<div class="post-metadata">

### Author: ![joebuhlig](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joebuhlig/32/193054_2.png) [@joebuhlig](https://meta.discourse.org/u/joebuhlig)
#### Post date: [January 25, 2017, 8:11pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/10 "2017-01-25T20:11:50Z")

</div>

It’s on the outlet itself when I change it to this:

`{{plugin-outlet name="above-static" args=(hash model=model showCreateAccount=(action "showCreateAccount"))}}`

---

<div class="post-metadata">

### Author: ![eviltrout](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/eviltrout/32/5275_2.png) [@eviltrout](https://meta.discourse.org/u/eviltrout)
#### Post date: [January 25, 2017, 8:15pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/11 "2017-01-25T20:15:13Z")

</div>

How are you triggering the action though?

---

<div class="post-metadata">

### Author: ![joebuhlig](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joebuhlig/32/193054_2.png) [@joebuhlig](https://meta.discourse.org/u/joebuhlig)
#### Post date: [January 25, 2017, 8:16pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/12 "2017-01-25T20:16:59Z")

</div>

I don’t get that far. I didn’t add the action to the connector at all.

---

<div class="post-metadata">

### Author: ![eviltrout](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/eviltrout/32/5275_2.png) [@eviltrout](https://meta.discourse.org/u/eviltrout)
#### Post date: [January 25, 2017, 8:19pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/13 "2017-01-25T20:19:18Z")

</div>

Oh I see, the error is trying to attach it! The error is because `showCreateAccount` doesn’t belong to the application controller, it’s part of the application route itself. Instead you can pass it the same way `site-header` does:

`showCreateAccount=(action "appRouteAction" "showCreateAccount")`

---

<div class="post-metadata">

### Author: ![joebuhlig](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joebuhlig/32/193054_2.png) [@joebuhlig](https://meta.discourse.org/u/joebuhlig)
#### Post date: [January 25, 2017, 8:20pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/14 "2017-01-25T20:20:45Z")

</div>

That gives me this:

`An action named 'appRouteAction' was not found in <(subclass of Ember.Controller):ember1073>`

Edit:  
Here’s the exact outlet I’m working with now:

`{{plugin-outlet name="above-static" args=(hash model=model showCreateAccount=(action "appRouteAction" "showCreateAccount"))}}`

---

<div class="post-metadata">

### Author: ![eviltrout](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/eviltrout/32/5275_2.png) [@eviltrout](https://meta.discourse.org/u/eviltrout)
#### Post date: [January 25, 2017, 8:23pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/15 "2017-01-25T20:23:23Z")

</div>

Ah, the static controller doesn’t have the `appRouteAction` helper that the `application` controller does. This is a bit of a complicated situation I promise, because it involves sending an action to something that is present on every page of the site 😛

Your best bet would be to create a new action in the static controller that simply calls `this.send('showCreateAccount')` and then bind _that_ to the plugin outlet.

---

<div class="post-metadata">

### Author: ![joebuhlig](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joebuhlig/32/193054_2.png) [@joebuhlig](https://meta.discourse.org/u/joebuhlig)
#### Post date: [January 25, 2017, 8:31pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/16 "2017-01-25T20:31:57Z")

</div>

Ok. I added it to the static controller and now I can see it in the Ember inspector on the controller. 👍 The trick is how to trigger that action from a `d-button` action within a connector. Wouldn’t I need another controller for that?

---

<div class="post-metadata">

### Author: ![eviltrout](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/eviltrout/32/5275_2.png) [@eviltrout](https://meta.discourse.org/u/eviltrout)
#### Post date: [January 25, 2017, 9:19pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/17 "2017-01-25T21:19:47Z")

</div>

Nope, if it’s passed into the outlet the connector has access to it. You should be able to do `{{d-button action=showCreateAccount}}` and it’ll find it.

---

<div class="post-metadata">

### Author: ![joebuhlig](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joebuhlig/32/193054_2.png) [@joebuhlig](https://meta.discourse.org/u/joebuhlig)
#### Post date: [January 25, 2017, 9:33pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/18 "2017-01-25T21:33:42Z")

</div>

That’s what I thought but it creates a loop of some kind:

 ![](https://global.discourse-cdn.com/meta/original/3X/f/a/faf4a596db8d26605390a16a935890f47b126422.jpg)

Here’s what I’m currently working with:

discourse/app/assets/javascripts/discourse/controllers/static.js.es6

```javascript
showCreateAccount(){
   this.send("showCreateAccount");
}

```

discourse/app/assets/javascripts/discourse/templates/static.hbs

```handlebars
{{plugin-outlet name="above-static" args=(hash model=model showCreateAccount=(action "showCreateAccount"))}}

```

my-plugin/assets/javascripts/discourse/templates/connectors/above-static/temp.hbs

```handlebars
{{d-button action=showCreateAccount class="btn-primary btn-large sign-up-button" label="signup_cta.sign_up" }}

```

---

<div class="post-metadata">

### Author: ![eviltrout](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/eviltrout/32/5275_2.png) [@eviltrout](https://meta.discourse.org/u/eviltrout)
#### Post date: [January 26, 2017, 3:55pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/19 "2017-01-26T15:55:08Z")

</div>

Looks like `this.send` is just caling the same `showCreateAccount` method over and over 🙂

Perhaps use a different name for your `showCreateAcount` action.

---

<div class="post-metadata">

### Author: ![joebuhlig](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joebuhlig/32/193054_2.png) [@joebuhlig](https://meta.discourse.org/u/joebuhlig)
#### Post date: [January 26, 2017, 4:07pm UTC](https://meta.discourse.org/t/using-a-discourse-component-in-a-plugin/56155/20 "2017-01-26T16:07:23Z")

</div>

> [@eviltrout](#):
>
> Looks like this.send is just caling the same showCreateAccount method over and over 🙂

Doh! That resolved it. It works! Thanks for sticking with me on this one.

Here’s a screen of this. You can see the sign up button in the background.

 ![](https://global.discourse-cdn.com/meta/original/3X/c/e/ce3be58cc63a52be3212f6d5eb5188027a977cd4.jpg)

Just for clarification purposes and for anyone who wants to submit a PR for their specific case, this is the setup:

discourse/app/assets/javascripts/discourse/controllers/static.js.es6

```javascript
showCreate(){
  this.send("showCreateAccount");
}

```

discourse/app/assets/javascripts/discourse/templates/static.hbs

```handlebars
{{plugin-outlet name="above-static" args=(hash model=model showCreateAccount=(action "showCreate"))}}

```

my-plugin/assets/javascripts/discourse/templates/connectors/above-static/temp.hbs

```handlebars
{{d-button action=showCreateAccount class="btn-primary btn-large sign-up-button" label="signup_cta.sign_up" }}

```
