対話グリッドの列の値の編集をインプレースではなく、ダイアログを別に開いて編集したい、という話があったので実装を考えてみました。その作業ログです。
実装の準備
最初にクイックSQLの以下のモデルから、表KVT_VALUESを作成します。
# prefix: kvt
# semantics: default
values
key vc8 /nn /unique
value vc4000
この表をソースとした対話グリッドのページを作成します。列VALUEがダイアログを開いて編集する対象になります。
名前をKey Value編集とした空のアプリケーションを作成します。ホームのページに対話グリッドのリージョンを追加します。
Content Body以下にリージョンを追加し、タイプを対話グリッド、ソースの表名にKVT_VALUESを選択します。
列が認識されるので、その中からIDを選択して、タイプを非表示、主キーをONに変更します。
対話グリッドのリージョンのAttributesを開いて、編集を有効にします(ONにします)。
続いて、選択された値を編集するためのダイアログとなるリージョンを作成します。Content Bodyにタイプが静的コンテンツとなるリージョンを作成します。外観のテンプレートをInline Dialogに変更します。
作成した静的コンテンツのリージョンに、変更する値を保持するページ・アイテムを作成します。以下では名前をP1_TEXTと設定しています。タイプはテキスト領域、ソースのフォーム・リージョンはNULL(選択しない)、タイプもNULL、使用とセッション・ステートの保持の選択は動作に影響を与えませんが、それぞれ、セッション・ステートの値がNULLの場合のみ、リクエストごと(メモリーのみ)とし、設定された値がセッション・ステートとして取り扱われない(永続化されない)ようにしておきます。
リージョンを閉じるためのボタンを追加します。ボタン名をB_CLOSEとし、動作のアクションは動的アクションで定義を選択します。
動的アクションの定義
編集したい列VALUEをクリックしたときにインライン・ダイアログを開く様にします。最初にクリックした対象を保持する変数elemをグローバル変数として定義します。ページのプロパティに含まれる、ファンクションおよびグローバル変数の宣言として以下を記載します。
var elem;
列VALUEがクリックされたときにダイアログを開く動的アクションを定義します。このとき、クリックした列VALUEに含まれる文字列を、ダイアログ上のページ・アイテムP1_TEXTに移入します。
列VALUEをクリックしたときに動的アクションが実行されるようにタイミングを設定します。以下の例では、イベントをクリック、選択タイプを列、リージョンはキー・バリュー、列はVALUEと設定しています。
列VALUEをクリックしたときに実行されるアクションを定義します。最初に列VALUEからページ・アイテムP1_TEXTへ文字列を移入するJavaScriptのコードを実行します。アクションをJavaScriptコードの実行とし、設定のコードに以下を記述します。
elem = this.triggeringElement;
$s("P1_TEXT", $v(elem));
文字列が移入できたところで、インライン・ダイアログを開きます。リージョンを開くためのアクションを定義します。影響を受ける要素は、選択タイプがリージョン、リージョンは値編集(インライン・ダイアログのリージョン名)としています。
次に、インライン・ダイアログ上のボタンB_CLOSEをクリックしたときに実行される動的アクションを定義します。タイミングはイベントがクリック、選択タイプはボタン、ボタンはB_CLOSEとします。
ボタンのクリック時に実行されるアクションとして、ページ・アイテムP1_TEXTに設定された値を、クリックした列VALUEに戻す処理を定義します。アクションとしてJavaScriptコードの実行を選択し、設定のコードに以下を記述します。
$s(elem, $v("P1_TEXT"));
続いて、開いているリージョンを閉じるアクションを定義します。アクションとしてリージョンを閉じるを選択し、影響を受ける要素として、選択タイプをリージョン、リージョンを値編集(インライン・ダイアログのリージョン)とします。
以上で最初のGIF動画で見ることができる実装になるはずです。
動的アクションの実行が列VALUEをクリックしたときではなく、列VALUEをクリックしてテキスト領域が開いた後に、そのテキスト領域をクリックして実行されるようになっているのは、ちょっと残念な感じではあります。
最新の対話グリッドでは列のタイプにテキスト領域、Markdownエディタ、リッチ・テキスト・エディタをそのまま指定できるので、基本的にこのような実装はしないのではないかと思います。列がJSONの場合であれば、直接JSONを記述するのも大変ですし、間違える可能性も大きいので、値の取り出しに次の様なコード(名前nameと年齢ageを含むJSONを仮定しています)、
elem = this.triggeringElement;
let v = $v(elem);
let jo = JSON.parse(v);
// $s("P1_TEXT", v);
$s("P1_NAME", jo.name);
$s("P1_AGE", jo.age);
値の設定に次の様なコードを設定することで、入力の助けにはなるでしょう。
// $s(elem, $v("P1_TEXT"));
let jo = {};
jo["name"] = $v("P1_NAME");
jo["age"] = Number($v("P1_AGE"));
$s(elem, JSON.stringify(jo));
確認に使用したアプリケーションのエクスポートを以下に置いておきます。
https://github.com/ujnak/apexapps/blob/master/exports/inlinedialogedit.sql
以上で今回の記事は終了です。Oracle APEXのアプリケーション開発の一助になれば幸いです。
完