2024年7月16日火曜日

インライン・ポップアップの表示位置を動的に変更する

対話モード・レポートのセルの位置に合わせて、インライン・ポップアップを表示させてみます。実装例として、サンプル・データセットEMP/DEPTの表EMPに含まれる列SALの値を、インライン・ポップアップを開いて変更できるようにします。

実装については、Philipp Hartenfellerさんによる以下の記事を参考にしています。
Oracle APEX anchored inline popups for data input
https://hartenfeller.dev/blog/apex-anchored-inline-popups

作成したサンプルは以下のように動作します。


表EMPをソースとした対話モード・レポートのページをひとつだけ含むAPEXアプリケーションを作成し、そのページにインライン・ポップアップを実装します。


ページ・デザイナで対話モード・レポートを含むページを開きます。

対話モード・レポートに静的IDとしてEMPを設定します。

インライン・ポップアップの表示位置を決める際に、仮の親エレメントとして対話モード・レポートのリージョンを使います。そのために対話モード・レポートに静的IDを設定します。


インライン・ポップアップを開く際に渡す従業員番号を保持するページ・アイテムとして、P1_EMPNOを作成します。タイプは非表示とします。動的アクションから設定するため、設定の保護された値はオフにします。画面上に保持されていればよいので、セッション・ステートのストレージはリクエストごと(メモリーのみ)を選択します。


給与の更新に失敗することがあります。表示するエラー・メッセージを保持するページ・アイテムとして、P1_ERRORを作成します。


更新する給与を指定する、インライン・ポップアップのリージョンを作成します。

識別の名前はUpdate Salary、タイプは静的コンテンツとします。レイアウトのスロットにDialogs, Drawers and Popupsを選択します。外観のテンプレートとしてInline Popupを選択します。

JavaScriptのコード(APEXアクション)からインライン・ポップアップのリージョンを開くため、詳細の静的IDとしてUPDATE_SALARYを設定します。

カスタム属性としてdata-parent-emelemt="#EMP"を指定します。インライン・ポップアップの表示位置は#EMP、つまり対話モード・レポートのリージョンではありませんが、data-parent-elementの評価はページ・ロード時に行われるため、ページ・ロード時に必ず存在しているHTML要素をdata-parent-elementに指定することにより、Popup Calloutの表示が適切に行われるように初期化します。


テンプレート・オプションを設定します。

Auto Height、Display Popup Calloutにチェックを入れます。サイズはNone、Callout PositionはDefaultとします。


Remove Page Overlayのチェックを外します。

Remove Page Overlayのチェックを外すと、インライン・ポップアップが開いたときにバックグラウンドがグレーに変わり、給与のリンクを含むバックグラウンドのどの位置をクリックしても、一旦ポップアップが閉じます。


Remove Page Overlayにチェックが入っていると、バックグラウンドはグレーアウトせず、給与のリンクをクリックすると、すでに開いているポップアップが閉じて新たにポップアップが開きます。


この操作を行うと、インライン・ポップアップの表示位置がずれます。位置のずれが気になる場合は、Remove Page Overlayのチェックを外します。


Display Popup Calloutのチェックが入っていると、ポップアップに親エレメントを指す山が表示されます。


別セッションで給与が更新されている場合に上書き更新を避けるため、変更前の給与を保持するページ・アイテムP1_SAL_OLDを作成します。

識別のタイプは非表示、設定の保護された値はオフにします。外観の書式マスクには、対話モード・レポートの列SALに設定されている書式マスクと同じ値を設定します。セッション・ステートのストレージは、リクエストごと(メモリーのみ)です。


更新する給与を入力するページ・アイテムとしてP1_SALを作成します。

タイプは数値フィールド、ラベルはSalaryとします。外観の書式マスクはP1_SAL_OLDと同様に、対話モード・レポートの列SALに合わせます。セッション・ステートのストレージはリクエストごと(メモリーのみ)です。


給与の更新を実行するボタンUPDATE_SALARYを作成します。動作のアクションに、動的アクションとして定義を選びます。


動的アクションの識別の名前はUpdate Salaryとします。ボタンのクリックで実行します。


最初のTRUEアクションでPL/SQLコードを実行し、給与を更新します。アクションとしてサーバー側のコードを実行を選択し、設定のPL/SQLコードとして以下を記述します。

送信するアイテムとして、P1_EMPNO、P1_SAL_OLD、P1_SAL、戻すアイテムとしてP1_ERRORを設定します。実行の初期化時に実行はオフです。


PL/SQLの実行でエラーが発生すると、表示すべきエラー・メッセージがP1_ERRORに戻されます。続くアクションを作成し、識別の名前をエラーの表示、タイプとしてJavaScriptコードの実行を選択します。クライアント側の条件のタイプにアイテムはnullではない、アイテムとしてP1_ERRORを指定することで、エラー・メッセージが返された場合に限り、エラー・メッセージを表示します。

設定のコードに以下を記述します。



給与の更新に成功した場合(エラー・メッセージのアイテムP1_ERRORがnullの場合)、インライン・ポップアップのリージョンを閉じます。


最後に給与の更新の有無に関わらず、対話モード・レポートをリフレッシュします。


対話モード・レポートの列SALをクリックしたときに、インライン・ポップアップを開くAPEXアクションを実行します。

列SALの列の書式のHTML式に以下を記述します。カスタム属性のdata-actionに、APEXアクションopen-update-salaryを呼び出す指定をします。


SALのセルをクリックしたときに呼び出されるAPEXアクションを設定します。

ページ・プロパティのJavaScriptのページ・ロード時に実行に、以下を記述します。Popup Calloutの表示が不要であれば、親エレメントの指定は若干簡単になります。


表示されているインライン・ポップアップをよく見ると、余計な下線が見つかります。


この下線はポップアップのminHeightの設定が表示されているみたいなので、ポップアップの表示前に以下の一行を入れることにより、表示されないようにできます。

popup.options.minHeight = null;

以上で実装は完了です。

今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/locating-inline-popup.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。

完