# איך להזריק שירות ל-Discourse?

**URL:** https://meta.discourse.org/t/how-to-inject-a-service-in-discourse/217533
**Category:** Development
**Created:** [8 בפברואר,‏ 2022,‏ 5:00pm UTC](https://meta.discourse.org/t/how-to-inject-a-service-in-discourse/217533 "2022-02-08T17:00:11Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![JQ331](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@JQ331](https://meta.discourse.org/u/JQ331)
#### Post date: [8 בפברואר,‏ 2022,‏ 5:00pm UTC](https://meta.discourse.org/t/how-to-inject-a-service-in-discourse/217533/1 "2022-02-08T17:00:11Z")

</div>

I want to use a service in a theme component I am building. If services are only available in plugins, I can build a plugin as well. Goal is to connect two different plugin outlets - press a button in one outlet, and have that button press picked up by the other outlet.

How can I properly register a service in Discourse? I’ve followed the topic [here](https://meta.discourse.org/t/using-ember-services-in-discourse-plugins/51713), and the related plugin code on github, but I’m not able to get it to work.

I think the missing piece is that my theme component is not recognizing the service. (Tried it in a plugin too, with same result).

* * *

Here’s some code I’ve tried:

**javascripts/discourse/services/great-stuff.js:**

```plaintext
import Service, { inject as service } from "@ember/service";

export default class GreatStuffService extends Service {
    call() {
        console.log('you called it')
    }
}

```

**connectors/topic-list-after-title/sample-outlet.js.es6** :

```plaintext
import { inject as service } from "@ember/service";

export default {
  greatStuff: service(),
  actions: {
      buttonPressInOutlet(){
         this.greatStuff.call() 
     }
  }
}

```

When I call the action “buttonPressInOutlet()” I get the error: `Uncaught TypeError: Cannot read properties of undefined (reading 'call')`.

What else is required?

---

<div class="post-metadata">

### Author: ![fzngagan](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/fzngagan/32/259349_2.png) [@fzngagan](https://meta.discourse.org/u/fzngagan)
#### Post date: [8 בפברואר,‏ 2022,‏ 5:30pm UTC](https://meta.discourse.org/t/how-to-inject-a-service-in-discourse/217533/2 "2022-02-08T17:30:22Z")

</div>

You might want to look at how other services are written. I don’t think the `x extends y` syntax works yet on the ember version discourse uses.

Also you might want to look at the `appEvents` api to communicate between two components.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [8 בפברואר,‏ 2022,‏ 5:56pm UTC](https://meta.discourse.org/t/how-to-inject-a-service-in-discourse/217533/3 "2022-02-08T17:56:03Z")

</div>

The problem here is that the ‘connector’ is not an EmberObject, and so you can’t inject things into it. Instead, you’ll need to create an Ember Component and inject it there.

Your ‘connector’ template would then look something like

```plaintext
{{my-component-name}}

```

Here’s an example of how that’s done in the whos-online plugin:

We have a service in core:

> <https://github.com/discourse/discourse/blob/5a93ce421da4e52b9d649cf609cd7d79d21a1683/app/assets/javascripts/discourse/app/services/presence.js#L246>

A connector template in the plugin

> <https://github.com/discourse/discourse-whos-online/blob/db7af7bce84240c47b4b51242451a5bd1c56949c/assets/javascripts/discourse/templates/connectors/discovery-list-container-top/online_users_widget.hbs#L1>

The component definition:  
[https://github.com/discourse/discourse-whos-online/blob/main/assets/javascripts/discourse/components/whos-online.js#L6-L7](https://github.com/discourse/discourse-whos-online/blob/main/assets/javascripts/discourse/components/whos-online.js#L6-L7)

(or you can use `export default Component.extend({ whosOnline: service() })` if you prefer)

And the component template:  
[https://github.com/discourse/discourse-whos-online/blob/main/assets/javascripts/discourse/templates/components/whos-online.hbs](https://github.com/discourse/discourse-whos-online/blob/main/assets/javascripts/discourse/templates/components/whos-online.hbs)

---

<div class="post-metadata">

### Author: ![JQ331](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@JQ331](https://meta.discourse.org/u/JQ331)
#### Post date: [8 בפברואר,‏ 2022,‏ 6:58pm UTC](https://meta.discourse.org/t/how-to-inject-a-service-in-discourse/217533/4 "2022-02-08T18:58:45Z")

</div>

> [@Faizaan Gagan](#):
>
> Also you might want to look at the `appEvents` api to communicate between two components.

I hadn’t thought of that. Thanks for the idea!

* * *

@david: thank you very much for this explanation and code examples. With those examples, I’ve been able to get it to work to click a button in in a component, and have it call an action in the service. That’s a big step forward.

Now I’m trying to sort through the other half–once an action is called in a service, have that trigger an action in a component. I figure it’s something like, in the service, importing the component and calling a function in that component (and/or subscribing to the action in the component). But I haven’t quite got the syntax yet.

Assuming that’s right, do you have any example syntax?

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [8 בפברואר,‏ 2022,‏ 7:17pm UTC](https://meta.discourse.org/t/how-to-inject-a-service-in-discourse/217533/5 "2022-02-08T19:17:55Z")

</div>

Calling a component method from a service isn’t really best practice, and Ember doesn’t provide an easy way to do it. There can be multiple instances of a component, so how would the service know which one to trigger the action on?

That said, sometimes it can be necessary to get something working within the confines of the Discourse plugin outlet system.

I’d recommend the same as @fzngagan - take a look at appEvents. They’re probably the cleanest way to trigger component logic from a service.

---

<div class="post-metadata">

### Author: ![JQ331](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@JQ331](https://meta.discourse.org/u/JQ331)
#### Post date: [8 בפברואר,‏ 2022,‏ 7:24pm UTC](https://meta.discourse.org/t/how-to-inject-a-service-in-discourse/217533/6 "2022-02-08T19:24:20Z")

</div>

> [@David Taylor](#):
>
> Calling a component method from a service isn’t really best practice, and Ember doesn’t provide an easy way to do it.

I had thought that is what [evented](https://stackoverflow.com/questions/60799589/use-of-ember-evented-in-a-service-for-publishing-subscribing-to-events) was meant for, but I haven’t used it before. The goal is just to get an ipc-like setup where

- user clicks button in component A
- that click causes data to load in component B

I’m more familiar with Angular, where creating then subscribing to a service would be the general way to do it. But in Discourse the best way is appEvents?

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [8 בפברואר,‏ 2022,‏ 7:39pm UTC](https://meta.discourse.org/t/how-to-inject-a-service-in-discourse/217533/7 "2022-02-08T19:39:22Z")

</div>

> [@JQ331](#):
>
> I had thought that is what [evented](https://stackoverflow.com/questions/60799589/use-of-ember-evented-in-a-service-for-publishing-subscribing-to-events) was meant for

Exactly! `appEvents` is a wrapper for `Evented`. If you prefer to use Evented directly then that’s also fine 👍

[https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/services/app-events.js#L4](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/services/app-events.js#L4)

---

<div class="post-metadata">

### Author: ![JQ331](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@JQ331](https://meta.discourse.org/u/JQ331)
#### Post date: [8 בפברואר,‏ 2022,‏ 7:48pm UTC](https://meta.discourse.org/t/how-to-inject-a-service-in-discourse/217533/8 "2022-02-08T19:48:28Z")

</div>

> [@David Taylor](#):
>
> Exactly! `appEvents` is a wrapper for `Evented` . If you prefer to use Evented directly then that’s also fine 👍
> 
> [https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/services/app-events.js#L4](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/services/app-events.js#L4)

🙂 Interesting! Thanks for the follow-up. I’m not partial to evented - never used it before and I was struggling a bit with the syntax in a Discourse service:  
`export default class GreatStuffService extends Service.extends(Evented, {...})`  
is not quite right.

Haven’t used appEvents before either. Am I able to create a new appEvent in a plugin/theme-component that I can then subscribe to? Most examples I am finding are about subscribing to appEvents that are set out already in Discourse core.

---

<div class="post-metadata">

### Author: ![fzngagan](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/fzngagan/32/259349_2.png) [@fzngagan](https://meta.discourse.org/u/fzngagan)
#### Post date: [8 בפברואר,‏ 2022,‏ 8:46pm UTC](https://meta.discourse.org/t/how-to-inject-a-service-in-discourse/217533/9 "2022-02-08T20:46:34Z")

</div>

> [@JQ331](#):
>
> I able to create a new appEvent in a plugin/theme-component that I can then subscribe to?

Yes you can do that. lookup `appEvents.trigger`
