2024年6月19日水曜日

動的アクションでサーバー側のコードの実行結果を条件としてJavaScriptを実行する

動的アクションでサーバー側のコードを実行した後に、その結果を条件としてクライアント側の処理(実際にはブラウザ上でのJavaScriptの実行)を切り替えるための設定を紹介します。

以下のGIF動画のような実装を行います。Countの値はデータベース側でセッション・ステートとして保持します。この値が0より大きいときはボタンINCホットにして、ボタンDEC通常の状態にします。逆に0以下であるときはボタンDECホットにして、ボタンINC通常の状態にします。


以下に実装を紹介します。

空のAPEXアプリケーションを作成し、デフォルトで作成されるホーム・ページにすべてを実装します。

ボタンとアイテムを配置するリージョンを作成します。

このリージョンの識別タイトルItemタイプ静的リージョンとします。リージョンの両端にボタン、中央にページ・アイテムを配置するために、外観テンプレートとしてItem Containerを選択します。


ボタンをクリックした数を保持するページ・アイテムとしてP1_COUNTを作成します。

タイプ数値フィールドラベルCountとします。リージョンItemに配置するため、レイアウトリージョンItem位置Itemを選択します。デフォルトタイプとして静的を選択し、静的値としてを指定します。

セッション・ステートストレージとしてセッションごと(永続)を選択し、このページ・アイテムの値がサーバー側(つまりデータベース)で保存されるようにします。


ページ・アイテムP1_COUNTの値を1増やすボタンINCを作成します。

レイアウトリージョンItem位置Button Startを選びます。動作アクション動的アクションで定義します。


同様に、ページ・アイテムP1_COUNTの値を1減らすボタンDECを作成します。

レイアウトリージョンItem位置Button Endを選びます。動作アクション動的アクションで定義します。


以上で準備ができました。

これから本記事の本題である動的アクションを作成します。

ボタンINC動的アクションを作成します。

識別名前onClick INCとします。タイミングはデフォルトでタイミングクリック選択タイプボタンボタンとしてINCが設定されます。


ボタンINCをクリックしたときに、最初にサーバー側のコードを実行します。

識別アクションとしてサーバー側のコードを実行を選択します。PL/SQLコードとして以下を記述します。

:P1_COUNT := :P1_COUNT + 1;

このコードはデータベース側で実行されますが、現在開いているページ上のページ・アイテムP1_COUNTの値とサーバー側でセッション・ステートとして保持しているP1_COUNTの値が一致しているとは限りません。

ページ・アイテムP1_COUNTの値はブラウザ上で手入力できます。そのような方法でブラウザ上で変更された値は、サーバー側の処理を行う前にサーバー側に送信する必要があります。そのために、送信するアイテムとしてP1_COUNTを指定します。送信するアイテムは複数指定することができます。

サーバー側のコードを実行した結果として、セッション・ステートのP1_COUNTに1が追加されますが、この値はサーバー側(つまりデータベース)で更新されただけで、そのままではブラウザ上のP1_COUNTの値(表示されている値)に反映されません。ブラウザ上の値も更新されるように、戻すアイテムとしてP1_COUNTを指定します。

実行の結果を待機オンにしています。このサーバー側のコードの実行の後にブラウザ側の処理を行いますが、実行の結果を待機オンにすることにより、このサーバー側のコードが実行された後(つまりサーバー側の実行結果であるP1_COUNTの値がブラウザに反映された後)に、ブラウザ側の処理が行われることを保証します。


ページ・アイテムP1_COUNTの値が0より大きいときに、ボタンINCホットにするTRUEアクションを作成します。

識別名前INC: HOT if Count > 0とします。アクションとしてクラスの追加を選択します。宣言的に定義していますが、実際の処理は影響を受ける要素として指定した要素のclassList.addを呼び出して、設定クラス(ここではu-hot)を追加するJavaScriptのコードが実行されます。

設定クラスu-hotを指定します。このCSSクラスu-hotはOracle APEXのUniversal ThemeのColor and Status Modifiersとして定義されています。

直接色を指定するのではなく、Universal Themeに定義されたクラスを使って色を指定することにより、アプリケーションを通した色使いの一貫性が保たれます。テーマ・ローラーを使ったり、CSS変数を変更することにより、u-hotとして定義されている色を変更することができます。

実行初期化時に実行オンにすることにより、ページを開いた時のP1_COUNTの値を元にボタンの色付けを行います。動的アクションは設定したタイミングで実行されますが、初期化時に実行オンにすることにより、ページを開いた時の初期状態としてボタンの色を決めることができます。

クライアントの条件タイプとしてアイテム > 値アイテムとしてP1_COUNTを設定します。クライアント側の条件は、ブラウザ側で判断されます。そのため、アイテムとして指定されたP1_COUNTの値は、ブラウザ上で保持している値を参照します。

このクライアント側の条件サーバー側の条件は名前は似ていますが、評価されるタイミングは全く異なります。サーバー側の条件はページが描画される際に(ページ生成を実行している)データベースで評価されます。サーバー側の条件としてtrueになった場合は、その動的アクションが生成されたページに(HTMLやJavaScriptとして)含まれます。逆にfalseの場合は、その動的アクションそのものがページに含まれません。


この他に作成する処理は、上記と同じ考え方に基づいて作成します。

ページ・アイテムP1_COUNTの値が0より大きいときに、ボタンDEC標準にするTRUEアクションを作成します。

識別名前DEC: CLEAR if Count > 0とします。アクションとしてクラスの削除を選択します。

設定クラスu-hot影響を受ける要素選択タイプボタンボタンDECです。この他は同じ設定になります。


ボタンDEC動的アクションを作成します。名前はonClick DECとします。タイミングはボタンのデフォルトです。


ボタンDECをクリックしたときに実行するサーバー側のコード以下になります。それ以外はボタンINCと同じです。

:P1_COUNT := :P1_COUNT - 1;


P1_COUNTの値が0以下になったときに、ボタンDECホットにするTRUEアクションを作成します。

識別名前DEC: HOT if Count <= 0とします。

クライアント側の条件タイプとしてアイテム <= 値を選択します。


P1_COUNTの値が0以下になったときに、ボタンINC標準にするTRUEアクションを作成します。


今回の記事は以上です。

作成したAPEXアプリケーションのエクスポートを以下に置きました。https://github.com/ujnak/apexapps/blob/master/exports/exec-javascript-based-on-server-side-result.zip

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