2021年2月12日金曜日

対話グリッドの列の値をダイアログを開いて編集する

 対話グリッドの列の値の編集をインプレースではなく、ダイアログを別に開いて編集したい、という話があったので実装を考えてみました。その作業ログです。


実装の準備


最初にクイック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のアプリケーション開発の一助になれば幸いです。