如何在 discourse 中注入服务?

我想在我正在构建的主题组件中使用一项服务。如果服务仅在插件中可用,我也可以构建一个插件。目标是连接两个不同的插件出口——在一个出口中按下按钮,然后让另一个出口接收到该按钮的按下。

我该如何正确地在 Discourse 中注册一项服务?我已按照此处的主题以及 GitHub 上相关的插件代码进行操作,但未能使其生效。

我认为缺失的一环是我的主题组件无法识别该服务。(在插件中也尝试过,结果相同)。


以下是我尝试过的一些代码:

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

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:

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

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

当我调用操作 “buttonPressInOutlet()” 时,我收到错误:Uncaught TypeError: Cannot read properties of undefined (reading 'call')

还需要什么?

您可能需要查看其他服务是如何编写的。我不认为 x extends y 语法在 Discourse 使用的 Ember 版本中还可用。

另外,您可能需要查看 appEvents API 来在两个组件之间进行通信。

2 个赞

这里的问题在于“连接器”不是 EmberObject,因此您无法在其上注入内容。您需要创建一个 Ember 组件并将其注入其中。

您的“连接器”模板看起来会像这样:

{{my-component-name}}

以下是“whos-online”插件中实现此功能的方法示例:

我们在核心中有一个服务:

插件中的连接器模板

组件定义:
https://github.com/discourse/discourse-whos-online/blob/main/assets/javascripts/discourse/components/whos-online.js#L6-L7

(如果您愿意,也可以使用 export default Component.extend({ whosOnline: service() })

以及组件模板:
https://github.com/discourse/discourse-whos-online/blob/main/assets/javascripts/discourse/templates/components/whos-online.hbs

3 个赞

我没想过这个。感谢您的建议!


@david:非常感谢您的解释和代码示例。通过这些示例,我已经能够实现点击组件中的按钮,并让它调用服务中的操作。这是一个很大的进步。

现在我正在尝试解决另一半问题——一旦服务中的操作被调用,如何触发组件中的操作。我想这就像在服务中导入组件并调用该组件中的函数(和/或订阅组件中的操作)。但我还没有完全掌握语法。

如果这是对的,您有示例语法吗?

从服务调用组件方法并不是最佳实践,Ember 也没有提供简单的方法来做到这一点。组件可以有多个实例,那么服务如何知道要触发哪个实例的动作呢?

话虽如此,但在 Discourse 插件出口系统的限制内完成某些工作有时是必要的。

我推荐 @fzngagan 的方法——查看 appEvents。它们可能是从服务触发组件逻辑的最简洁的方式。

2 个赞

我曾以为 evented 就是为此而设计的,但我以前从未使用过它。目标只是建立一个类似 ipc 的设置,其中:

  • 用户单击组件 A 中的按钮
  • 该单击导致组件 B 中的数据加载

我更熟悉 Angular,其中创建然后订阅服务是通常的做法。但在 Discourse 中,最好的方法是 appEvents 吗?

没错!appEventsEvented 的一个包装器。如果你更喜欢直接使用 Evented,那也是可以的 :+1:

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

1 个赞

:slight_smile: 有趣!感谢跟进。我对 evented 并不偏爱——以前从未使用过它,并且在 Discourse 服务的语法上遇到了一些困难:
export default class GreatStuffService extends Service.extends(Evented, {...})
不太对。

以前也从未使用过 appEvents。我能否在插件/主题组件中创建一个新的 appEvent,然后订阅它?我找到的大多数示例都是关于订阅 Discourse 核心中已设置好的 appEvents。

1 个赞

可以,你可以这样做。查找 appEvents.trigger

2 个赞