Discourseでサービスを注入する方法

テーマコンポーネントでサービスを使用したいと考えています。サービスがプラグインでのみ利用可能であれば、プラグインを作成することもできます。目標は、2つの異なるプラグインのアウトレットを接続することです。つまり、一方のアウトレットでボタンを押し、そのボタンのプレスをもう一方のアウトレットで検出できるようにすることです。

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')」というエラーが発生します。

他に何が必要ですか?

他のサービスがどのように記述されているか確認した方が良いかもしれません。Discourseが使用しているEmberのバージョンでは、x extends y構文はまだ機能しないと思います。

また、2つのコンポーネント間で通信するためにappEvents APIを確認した方が良いかもしれません。

「いいね!」 2

ここで問題なのは、「コネクタ」がEmberObjectではないため、そこにものを注入できないことです。代わりに、Ember Componentを作成し、そこに注入する必要があります。

「コネクタ」のテンプレートは、次のようになります。

{{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