テーマコンポーネント/ウィジェットでページが読み込まれているかどうかを確認する方法

どうも、ここで見落としていることがありそうな気がするのですが、どうしてもわかりません。テーマコンポーネントでいくつかのウィジェットを読み込んでいるのですが、ユーザーが新しいページに移動した後にそれらを再描画するために、以下のようなコード(カテゴリバナーから借用したもの)を使用しています。

api.decorateWidget("my-widget:after", (helper) => {
    helper.widget.appEvents.on("page:changed", () => {
      helper.widget.scheduleRerender();
    })
});

しかし、このコードは新しいページが読み込まれた後にウィジェットを更新するまで待ってしまいます。目指しているのは、誰かが別のページへのリンクをクリックした瞬間にウィジェットの内容を非表示にすることです。これは、ネイティブの Discourse 機能のように、クリック直後に何かを非表示にしてローディングスピナーを表示するのと同様の動作です。

app/assets/javascripts/discourse/app/templates/discovery.hbs には、div コンテナが「loading」という変数を監視しているようですが、それがどこから来ているのか、またどのようにそれに「接続」するか、あるいは自分のウィジェットでローディング状態を監視するかがわかりません。

回答や、少なくとも方向性を示していただければ幸いです。:slight_smile:

ありがとうございます、

Zach

「いいね!」 1

このスレッドを再度浮上させたいと思います。必要であれば、プレミアムサポートにお金を払ってでも回答を得る用意があります。

どのような動作が望ましく、どの特定のページでそれを求めるか、簡潔にご説明いただけますか?

scheduleRerender() の代わりに queueRerender() を試してみてください。

ご返信ありがとうございます。

特定のカテゴリページ用にいくつかのウィジェットを作成しているのですが、理想的にはページを移動した瞬間にそれらを非表示にしたいと考えています。目指している動作のデモ動画(45 秒)はこちらです:Google Chrome - Latest Rental Cities/California topics - Afford Anything Forums - Google Chrome | Loom

@hawm さん、キューによる再レンダリングは今回必要ないかもしれません。これはウィジェットを再レンダリングすることではなく、グローバルな Discourse アプリが新しいページを読み込んでいるかどうかをウィジェット自身が認識できるようにすることに関わる問題だからです。

シンプルに言えば、条件はテンプレート内に記述すべきです。例えば:

{{#if xyz}}
あなたのコード
{{/if}}

Ember のテンプレートは動的です。値が変更されると、ウィジェットは非表示になります。

はい、もちろんです :slight_smile: if/then の構文に困っているわけではありません。Discourse が現在新しいページをロードしているかどうかを確認する方法があるかどうかをお聞きしています。

modifyClass API を使用して discovery ルートをハックし、カスタムイベントをトリガーすることで実現できると思います。

https://api.emberjs.com/ember/3.12/classes/Route

loading 変数は、前述の discovery ルートから提供されています。plugin-outlet にアタッチされたウィジェットは、この変数が引数として渡されていないため、アクセスできない可能性があります。これは plugin-outlet の定義次第です。

ありがとうございます。調べてみますので、見つかったら解決策を記録として更新しますね :slight_smile:

「いいね!」 1

ついに解決策を見つけました。これにはとても長い時間を費やしましたが、コア機能としてマージする価値があると思います。正直、最初からコアに存在すべきだったと感じるからです。

以下のコードをテーマコンポーネントに追加しました。これは、ルーティングが開始されるとすぐに body に「loading」クラスを追加し、ルーティングが完了するとすぐにそれを削除するものです。Ember に詳しい方にとっては簡単で自明なことかもしれませんが、私には途方もない時間がかかりました(無数の試行と、ここで見つけられるすべてのスレッドの読み込み)。

このコアコードがあれば、異なるウィジェットにローディングスピンナーなどを追加できます。body タグに loading CSS クラスがあるかどうかによって、それらの CSS と表示/非表示を制御できるようになります。

initialize() {
    withPluginApi("0.8.8", (api) => {
      const router = api._lookupContainer('router:main');
      router.reopen({
        addLoadingCSSClassToBody: function() {
          document.body.classList.add("loading");
        }.on('willTransition')
      });

      router.reopen({
        removeLoadingCSSClassFromBody: function() {
          document.body.classList.remove("loading");
        }.on('didTransition')
      });
    });
  },
};
「いいね!」 1

共有しているコードはウィジェットからではなく、こちらでダウンロード用にリリースしたコンポーネントからのものです meta

これではルーターと @discourseComputed を併用して、ルートが変更されたかを確認し、それに基づいてレンダリングを行います。

動作について詳しく知りたい場合は、コードをさらに確認してみてください。

「いいね!」 4