どうも、ここで見落としていることがありそうな気がするのですが、どうしてもわかりません。テーマコンポーネントでいくつかのウィジェットを読み込んでいるのですが、ユーザーが新しいページに移動した後にそれらを再描画するために、以下のようなコード(カテゴリバナーから借用したもの)を使用しています。
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」という変数を監視しているようですが、それがどこから来ているのか、またどのようにそれに「接続」するか、あるいは自分のウィジェットでローディング状態を監視するかがわかりません。
回答や、少なくとも方向性を示していただければ幸いです。
ありがとうございます、
Zach
「いいね!」 1
このスレッドを再度浮上させたいと思います。必要であれば、プレミアムサポートにお金を払ってでも回答を得る用意があります。
fzngagan
(Faizaan Gagan)
2021 年 5 月 19 日午前 10:11
3
どのような動作が望ましく、どの特定のページでそれを求めるか、簡潔にご説明いただけますか?
hawm
(Hawm)
2021 年 5 月 19 日午前 11:16
4
scheduleRerender() の代わりに queueRerender() を試してみてください。
eviltrout:
バインディングとコンテンツの再レンダリング
Ember を長く使っている方なら、ウィジェットが Embers のバインディングやオブザーバーシステムを使っていないのに、いつ再レンダリングが必要かどう知っているのか疑問に思うかもしれません。実際、これはウィジェットが受け入れる大きなトレードオフの一つです。Ember のビューレンダリングではこれが自動的に処理されますが、ウィジェットでは、ユーザーがウィジェットと対話したときのみ再レンダリングが必要であると想定しています。
ウィジェットが再レンダリングされるのは、以下のタイミングです。
ユーザーがウィジェットをクリックしたとき
何らかのアクションがトリガーされた後
アクションがプロミスを返した場合、そのプロミスが解決した後
上記のケースは、Discourse がウィジェットを再レンダリングする必要がある場合の圧倒的 な大部分を占めています。ただし、エッジケースがある場合、ウィジェットは this.queueRerender() を呼び出すことで自身を再レンダリングできます。
レンダリング呼び出しは Ember Run Loop で統合されるため、同じイベントループ内で this.queueRerender() を複数回呼び出しても心配する必要はありません。ウィジェットはキューに追加されたすべての変更に対して 1 回だけレンダリングされます。
ご返信ありがとうございます。
特定のカテゴリページ用にいくつかのウィジェットを作成しているのですが、理想的にはページを移動した瞬間にそれらを非表示にしたいと考えています。目指している動作のデモ動画(45 秒)はこちらです:Google Chrome - Latest Rental Cities/California topics - Afford Anything Forums - Google Chrome | Loom
@hawm さん、キューによる再レンダリングは今回必要ないかもしれません。これはウィジェットを再レンダリングすることではなく、グローバルな Discourse アプリが新しいページを読み込んでいるかどうかをウィジェット自身が認識できるようにすることに関わる問題だからです。
fzngagan
(Faizaan Gagan)
2021 年 5 月 19 日午後 1:14
6
シンプルに言えば、条件はテンプレート内に記述すべきです。例えば:
{{#if xyz}}
あなたのコード
{{/if}}
Ember のテンプレートは動的です。値が変更されると、ウィジェットは非表示になります。
はい、もちろんです if/then の構文に困っているわけではありません。Discourse が現在新しいページをロードしているかどうかを確認する方法があるかどうかをお聞きしています。
hawm
(Hawm)
2021 年 5 月 19 日午後 4:11
8
modifyClass API を使用して discovery ルートをハックし、カスタムイベントをトリガーすることで実現できると思います。
https://api.emberjs.com/ember/3.12/classes/Route
loading 変数は、前述の discovery ルートから提供されています。plugin-outlet にアタッチされたウィジェットは、この変数が引数として渡されていないため、アクセスできない可能性があります。これは plugin-outlet の定義次第です。
ありがとうございます。調べてみますので、見つかったら解決策を記録として更新しますね
「いいね!」 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