ajax呼び出し後にpluginOutletにコンテンツを手動で追加する方法は?また、pluginOutletを再レンダリングまたはリフレッシュするには?

こんにちは :wave:

Discourse のテーマと ember.js は初めてで、現在、メインのウェブサイトからのナビゲーション項目を持つテーマに取り組んでいます。

ナビゲーション項目 JSON は AJAX リクエストから取得され、2 つの場所に表示する必要があります。

1 番目の場所は header-buttons:before です。これは api.decorateWidget を使用し、site-header:force-refresh の appEvents をトリガーすることで実現できました。

ajax( settings.site_navigation_links_endpoint ).then((result) => {

	if (!result.length) {
		return;
	}

	result.map((customHeaderLinksArray) => {

		const anchorAttributes = {
			title  : customHeaderLinksArray.title,
			href   : customHeaderLinksArray.url,
			target : "self"
		};

		headerLinks.push(
			h(
				`li.custom-header-nav-item`,
				h( "a.custom-header-nav-item-link", anchorAttributes, customHeaderLinksArray.title )
			)
		);

	});

	headerNav = h("ul.custom-header-nav", headerLinks);

	if( settings.site_navigation_position == "inline" ) {
		api.decorateWidget("header-buttons:before", (helper) => {
			return headerNav;
		});
	}

	appEvents.trigger("site-header:force-refresh");

	// 場所 (2番目の場所、下記参照) に表示するには
	// ...
	// ...
}

2 番目の場所は、below-site-header の pluginOutlet を介します。
これはウィジェットではないため、api.decorateWidget と同じことはできないと思います。

私の質問は次のとおりです。

  1. AJAX コンテンツを pluginOutlet に手動で挿入するにはどうすればよいですか?
  2. AJAX 呼び出し後に仮想 DOM をオンザフライでコンパイルする方法も知りたいですか?たとえば、上記の変数 headerNav をコンパイルされた HTML マークアップで取得したいです。どのライブラリ/関数を使用すればよいかわかりません。
  3. 可能であれば、pluginOutlet を再レンダリングする方法は? appEvents.trigger("site-header:force-refresh"); と似ていますか?

よろしくお願いします :man_bowing:

「いいね!」 2

その通りです。2つの方法があります。

  1. カスタマイズをウィジェットにし、次のようにプラグインのアウトレットにウィジェットをマウントします。

    {{mount-widget widget="widget-name"}}
    

    Discourse でウィジェットがどのように作成されるかの例(たとえば、ホームロゴ)は、discourse/app/assets/javascripts/discourse/app/widgets/home-logo.js at 2dbcea9eeeb816dda347027497b3a49634ef851f · discourse/discourse · GitHub で確認できます。

    テーマでは、widget-name.js ファイルを javascripts/discourse/widgets ディレクトリに追加します。

    ウィジェットに関する詳細は、A tour of how the Widget (Virtual DOM) code in Discourse works にありますが、ウィジェットは徐々に廃止される予定であるため、このプロセスで学んだことは長期的には役に立たないことに注意してください。

  2. ウィジェットデコレーターはそのままにして、プラグインのアウトレットで目的の操作を行う別の Ember コンポーネントを作成します。ウィジェットは、Discourse の大部分が構築されている Ember コンポーネントに置き換える形で廃止を進めています。

    このプロセスは次のようになります。

    1. テーマの javascripts/discourse/components ディレクトリにコンポーネントの JS ファイルと HBS ファイルを作成します。

      • component-name.js

      • component-name.hbs

    2. Ember コンポーネントをビルドします。残念ながら、このステップは基本的に「Ember を学ぶ」ことです (Ember Guides)。ただし、これは開始の目安になると思います。

      • component-name.js で:
      import Component from "@glimmer/component";
      import { tracked } from "@glimmer/tracking";
      import { action } from "@ember/object';
      
      const endpoint = settings.site_navigation_links_endpoint;
      
      export default class ComponentName extends Component {
        @tracked navLinks = null;
      
        @action
        async fetchNavLinks() {
          try {
            const response = await fetch(endpoint);
            const data = await response.json(); // これが JSON であると仮定します
            this.navLinks = data;
          } catch (error) {
            console.error("Failed:", error);
          }
        }
      }
      
      • component-name.hbs で:
      <div {{did-insert this.fetchNavLinks}}>
        {{#each this.navLinks as |link|}}
          <a href={{link.anchor}}>{{link.title}}</a>
        {{/each}}
      </div>
      

      これにより、コンポーネントが挿入されたとき(この場合は、Discourse サイトにアクセスしてアプリがレンダリングされたとき)に fetchNavLinks アクションが呼び出されます。navLinks が更新されるたびに、それが追跡対象のプロパティであるため、コンポーネントの内容も更新されます。

      コンポーネントのレンダリング時よりも頻繁にリンクを更新したい場合は、ここでの JS に追加のロジックを組み込む必要があります。たとえば、現在のルート(ページ)が特定の条件を満たしているかどうかを確認します。

    3. このコンポーネントは、javascripts/discourse/connectors/below-site-header/my-component-connector.hbs でアウトレットに追加することで、プラグインアウトレットに追加されます。

      <ComponentName />
      
「いいね!」 9

クリスさん、本当にありがとうございます!大変参考になりました。

ウィジェットは徐々に廃止されるため、コンポーネントを使用する2番目のアプローチを選択しました。.hbsファイルでの関数呼び出しの小さなタイポを除き、{{did-insert this. fetchNavLinks}}となるはずですが、すべて正常に動作しました!

did-insertがあることを知って安心しました。これでタスクは完了です。:man_bowing:

「いいね!」 1

ああ、気づいてくれて嬉しいです。上記の投稿を修正しました。

「いいね!」 1

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.