Comment injecter un service dans Discourse ? discourse ? discourse ? discourse ? discourse ?

Je veux utiliser un service dans un composant de thème que je construis. Si les services ne sont disponibles que dans les plugins, je peux aussi créer un plugin. L’objectif est de connecter deux points de sortie de plugin différents - appuyer sur un bouton dans une sortie, et que cet appui sur le bouton soit capté par l’autre sortie.

Comment puis-je enregistrer correctement un service dans Discourse ? J’ai suivi le sujet ici, et le code de plugin associé sur github, mais je n’arrive pas à le faire fonctionner.

Je pense que la pièce manquante est que mon composant de thème ne reconnaît pas le service. (J’ai essayé dans un plugin aussi, avec le même résultat).


Voici un code que j’ai essayé :

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()
     }
  }
}

Lorsque j’appelle l’action “buttonPressInOutlet()”, j’obtiens l’erreur : Uncaught TypeError: Cannot read properties of undefined (reading 'call').

Qu’est-ce qui est requis d’autre ?

Vous voudrez peut-être examiner comment les autres services sont écrits. Je ne pense pas que la syntaxe x extends y fonctionne encore sur la version d’Ember que Discourse utilise.

De plus, vous voudrez peut-être examiner l’API appEvents pour communiquer entre deux composants.

2 « J'aime »

Le problème ici est que le « connecteur » n’est pas un EmberObject, et vous ne pouvez donc pas y injecter des éléments. Au lieu de cela, vous devrez créer un composant Ember et l’y injecter.

Votre modèle « connecteur » ressemblerait alors à ceci :

{{my-component-name}}

Voici un exemple de la façon dont cela est fait dans le plugin whos-online :

Nous avons un service dans le cœur :

Un modèle de connecteur dans le plugin

La définition du composant :
https://github.com/discourse/discourse-whos-online/blob/main/assets/javascripts/discourse/components/whos-online.js#L6-L7

(ou vous pouvez utiliser export default Component.extend({ whosOnline: service() }) si vous préférez)

Et le modèle du composant :
https://github.com/discourse/discourse-whos-online/blob/main/assets/javascripts/discourse/templates/components/whos-online.hbs

3 « J'aime »

Je n’y avais pas pensé. Merci pour l’idée !


@david : merci beaucoup pour cette explication et ces exemples de code. Avec ces exemples, j’ai réussi à faire en sorte qu’un clic sur un bouton dans un composant appelle une action dans le service. C’est un grand pas en avant.

Maintenant, j’essaie de trier l’autre moitié : une fois qu’une action est appelée dans un service, qu’elle déclenche une action dans un composant. Je pense que c’est quelque chose comme, dans le service, importer le composant et appeler une fonction dans ce composant (et/ou s’abonner à l’action dans le composant). Mais je n’ai pas encore tout à fait la syntaxe.

En supposant que ce soit correct, avez-vous des exemples de syntaxe ?

Appeler une méthode de composant depuis un service n’est pas vraiment une bonne pratique, et Ember ne fournit pas de moyen simple de le faire. Il peut y avoir plusieurs instances d’un composant, alors comment le service saurait-il laquelle déclencher l’action ?

Cela dit, il peut parfois être nécessaire de faire fonctionner quelque chose dans les limites du système d’emboîtement de plugins de Discourse.

Je recommanderais la même chose que @fzngagan : jetez un œil à appEvents. C’est probablement le moyen le plus propre de déclencher la logique du composant à partir d’un service.

2 « J'aime »

Je pensais que c’était à cela que servait evented, mais je ne l’ai jamais utilisé auparavant. Le but est juste d’obtenir une configuration de type ipc où

  • l’utilisateur clique sur un bouton dans le composant A
  • ce clic provoque le chargement des données dans le composant B

Je suis plus familier avec Angular, où créer puis s’abonner à un service serait la manière générale de procéder. Mais dans Discourse, la meilleure façon est appEvents ?

Exactement ! appEvents est un wrapper pour Evented. Si vous préférez utiliser Evented directement, c’est également possible :+1:

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

1 « J'aime »

:slight_smile: Intéressant ! Merci pour le suivi. Je ne suis pas particulièrement attaché à evented - je ne l’ai jamais utilisé auparavant et j’ai eu un peu de mal avec la syntaxe dans un service Discourse :
export default class GreatStuffService extends Service.extends(Evented, {...})
n’est pas tout à fait correct.

Je n’ai pas non plus utilisé appEvents auparavant. Puis-je créer un nouvel appEvent dans un plugin/composant de thème auquel je peux ensuite m’abonner ? La plupart des exemples que je trouve concernent l’abonnement à des appEvents déjà définis dans le cœur de Discourse.

1 « J'aime »

Oui, vous pouvez le faire. Recherchez appEvents.trigger

2 « J'aime »