Как внедрить сервис в 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('вы вызвали это')
    }
}

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 пока не работает в версии Ember, которую использует Discourse.

Также можно обратиться к API appEvents для обмена данными между двумя компонентами.

Проблема здесь в том, что «connector» не является объектом EmberObject, поэтому в него нельзя внедрять зависимости. Вместо этого вам нужно создать компонент Ember и внедрить их туда.

Шаблон вашего «connector» будет выглядеть примерно так:

{{my-component-name}}

Вот пример того, как это реализовано в плагине whos-online:

У нас есть сервис в ядре:

Шаблон connector в плагине:

Определение компонента:
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

Я об этом не думал. Спасибо за идею!


@david: большое спасибо за это объяснение и примеры кода. С помощью этих примеров мне удалось заставить работать клик по кнопке в компоненте, который вызывает действие в сервисе. Это большой шаг вперёд.

Теперь я пытаюсь разобраться с другой половиной — как, после вызова действия в сервисе, запустить действие в компоненте. Я предполагаю, что это что-то вроде импорта компонента в сервис и вызова функции в этом компоненте (и/или подписки на действие в компоненте). Но я пока не совсем разобрался с синтаксисом.

Если я прав, есть ли у вас примеры синтаксиса?

Вызов метода компонента из сервиса — это не лучшая практика, и в Ember нет простого способа это сделать. Поскольку экземпляров компонента может быть несколько, как сервис узнает, на каком именно нужно инициировать действие?

Тем не менее, иногда необходимо заставить что-то работать в рамках системы плагинов Discourse.

Я рекомендую то же, что и @fzngagan: обратите внимание на appEvents. Это, вероятно, самый чистый способ запускать логику компонента из сервиса.

Мне казалось, что для этого предназначен evented, но я раньше его не использовал. Цель — создать механизм, похожий на IPC, где:

  • пользователь нажимает кнопку в компоненте A
  • это нажатие вызывает загрузку данных в компоненте B

Я больше знаком с Angular, где создание сервиса и подписка на него — это общий способ решения таких задач. Но в Discourse лучший способ — это appEvents?

Именно! appEvents — это обёртка для Evented. Если вы предпочитаете использовать Evented напрямую, это тоже отлично :+1:

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

:slight_smile: Интересно! Спасибо за уточнение. Я не сторонник Evented — никогда раньше его не использовал, и у меня возникли некоторые трудности с синтаксисом в сервисе Discourse:
export default class GreatStuffService extends Service.extends(Evented, {...})
работает не совсем правильно.

Раньше я тоже не использовал appEvents. Могу ли я создать новое событие appEvent в плагине или компоненте темы, чтобы затем подписаться на него? Большинство примеров, которые я нахожу, касаются подписки на уже существующие в ядре Discourse события appEvents.

Да, вы можете это сделать. Обратитесь к appEvents.trigger.