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') 오류가 발생합니다.

무엇이 더 필요한가요?

다른 서비스가 어떻게 작성되어 있는지 살펴보는 것이 좋습니다. 현재 Discourse가 사용하는 Ember 버전에서는 x extends y 구문이 아직 작동하지 않는 것 같습니다.

또한 두 컴포넌트 간에 통신하기 위해 appEvents API를 살펴보는 것도 좋습니다.

여기서 문제는 'connector’가 EmberObject가 아니기 때문에 그 안에 것을 주입(inject)할 수 없다는 점입니다. 대신 Ember Component를 생성하고 그곳에 주입해야 합니다.

그렇게 하면 ‘connector’ 템플릿은 다음과 같은 형태가 됩니다.

{{my-component-name}}

whos-online 플러그인에서 이렇게 하는 예시를 보여드리겠습니다:

core에 서비스가 있습니다:

플러그인 내의 커넥터 템플릿:

컴포넌트 정의:
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를 참고하세요.