2024年6月19日水曜日

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

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

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


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

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

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

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


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

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

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


ページ・アイテム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、値は0を設定します。クライアント側の条件は、ブラウザ側で判断されます。そのため、アイテムとして指定された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のアプリケーション作成の参考になれば幸いです。

完