JQ331
2022 年2 月 8 日 17:00
1
我想在我正在构建的主题组件中使用一项服务。如果服务仅在插件中可用,我也可以构建一个插件。目标是连接两个不同的插件出口——在一个出口中按下按钮,然后让另一个出口接收到该按钮的按下。
我该如何正确地在 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')。
还需要什么?
fzngagan
(Faizaan Gagan)
2022 年2 月 8 日 17:30
2
您可能需要查看其他服务是如何编写的。我不认为 x extends y 语法在 Discourse 使用的 Ember 版本中还可用。
另外,您可能需要查看 appEvents API 来在两个组件之间进行通信。
2 个赞
david
(David Taylor)
2022 年2 月 8 日 17:56
3
这里的问题在于“连接器”不是 EmberObject,因此您无法在其上注入内容。您需要创建一个 Ember 组件并将其注入其中。
您的“连接器”模板看起来会像这样:
{{my-component-name}}
以下是“whos-online”插件中实现此功能的方法示例:
我们在核心中有一个服务:
}
this.set("count", this.users.length);
} else {
// Unexpected message
await this._resubscribe();
return;
}
}
}
export default class PresenceService extends Service {
init() {
super.init(...arguments);
this._queuedEvents = [];
this._presenceChannelStates = EmberObject.create();
this._presentProxies = new Map();
this._subscribedProxies = new Map();
this._initialDataRequests = new Map();
if (this.currentUser) {
window.addEventListener("beforeunload", this._beaconLeaveAll);
插件中的连接器模板
组件定义:
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 个赞
JQ331
2022 年2 月 8 日 18:58
4
我没想过这个。感谢您的建议!
@david :非常感谢您的解释和代码示例。通过这些示例,我已经能够实现点击组件中的按钮,并让它调用服务中的操作。这是一个很大的进步。
现在我正在尝试解决另一半问题——一旦服务中的操作被调用,如何触发组件中的操作。我想这就像在服务中导入组件并调用该组件中的函数(和/或订阅组件中的操作)。但我还没有完全掌握语法。
如果这是对的,您有示例语法吗?
david
(David Taylor)
2022 年2 月 8 日 19:17
5
从服务调用组件方法并不是最佳实践,Ember 也没有提供简单的方法来做到这一点。组件可以有多个实例,那么服务如何知道要触发哪个实例的动作呢?
话虽如此,但在 Discourse 插件出口系统的限制内完成某些工作有时是必要的。
我推荐 @fzngagan 的方法——查看 appEvents。它们可能是从服务触发组件逻辑的最简洁的方式。
2 个赞
JQ331
2022 年2 月 8 日 19:24
6
我曾以为 evented 就是为此而设计的,但我以前从未使用过它。目标只是建立一个类似 ipc 的设置,其中:
用户单击组件 A 中的按钮
该单击导致组件 B 中的数据加载
我更熟悉 Angular,其中创建然后订阅服务是通常的做法。但在 Discourse 中,最好的方法是 appEvents 吗?
david
(David Taylor)
2022 年2 月 8 日 19:39
7
1 个赞
JQ331
2022 年2 月 8 日 19:48
8
有趣!感谢跟进。我对 evented 并不偏爱——以前从未使用过它,并且在 Discourse 服务的语法上遇到了一些困难:
export default class GreatStuffService extends Service.extends(Evented, {...})
不太对。
以前也从未使用过 appEvents。我能否在插件/主题组件中创建一个新的 appEvent,然后订阅它?我找到的大多数示例都是关于订阅 Discourse 核心中已设置好的 appEvents。
1 个赞
fzngagan
(Faizaan Gagan)
2022 年2 月 8 日 20:46
9
可以,你可以这样做。查找 appEvents.trigger
2 个赞