2023年7月6日木曜日

対話グリッドの選択リストの列に動的アクションで値を設定する

 対話グリッドの列に設定した値より、別の列の選択リストに値を設定する方法を紹介します。

以下の動画のように、列Product Name製品名を入力したときに、列Shop販売会社を設定します。列Shopに設定された販売会社は初期値で、選択リストを開いて変更できます。


以下のスクリプトを実行し、上記のサンプル・アプリケーションで使用するスキーマを作成します。

drop table shp_orders;
drop table shp_products;
drop table shp_shops;
/*
* 商店のマスター表
*/
create table shp_shops (
shop_code varchar2(1 char) primary key,
shop_name varchar2(80 char) not null
)
;
insert into shp_shops values('A','AM社');
insert into shp_shops values('B','BG社');
insert into shp_shops values('R','RT社');
insert into shp_shops values('Y','YD社');
/*
* 製品のマスター表
*/
create table shp_products (
id number generated by default on null as identity
constraint shp_products_id_pk primary key,
product_name varchar2(20 char) not null,
default_shop varchar2(1 char)
constraint shp_products_default_shop_fk
references shp_shops on delete cascade
)
;
create index shp_products_i1 on shp_products (default_shop);
insert into shp_products(product_name, default_shop) values('洗濯機','A');
insert into shp_products(product_name, default_shop) values('乾燥機','B');
insert into shp_products(product_name, default_shop) values('掃除機','R');
insert into shp_products(product_name, default_shop) values('食洗機','Y');
/*
* 発注の一覧
* 発注先の商店はdefault_shopとは限らない。
*/
create table shp_orders (
id number generated by default on null as identity
constraint shp_orders_id_pk primary key,
product_name varchar2(20 char) not null,
shop varchar2(1 char)
constraint shp_orders_shop_fk
references shp_shops on delete cascade
)
;
create index shp_orders_i1 on shp_orders (shop);

アプリケーション作成ウィザードを起動します。アプリケーションの名前選択リストの初期化とします。

ホーム・ページを削除し、代わりに対話グリッドのページを追加します。


対話グリッドのページは、以下の設定で作成します。

ページ名Orders表またはビュー編集を許可を選択します。

表またはビューとしてSHP_ORDERSを選択します。

詳細ホームページとして設定にチェックを入れます。


以上でアプリケーションの作成を実行します。

アプリケーションが作成されたら、ページ・デザイナで対話グリッドのページを開きます。

ページ・プロパティJavaScriptファンクションおよびグローバル変数の宣言に以下を記述します。

var defaultShops;

この変数defaultShopsは、製品名と販売会社の組み合わせをキャッシュするために使用します。


対話グリッドShp Ordersを選択し、静的IDとしてordersを設定します。


プロセス・ビューを開きます。

製品名より販売会社の初期値を求めるプロセスを、Ajaxコールバックとして作成します。

識別名前GET_DEFAULT_SHOPとします。この名前は、JavaScript側から呼び出すファンクションapex.server.processの引数として与えるため、変更はできません(変更する場合は、apex.server.processの引数も変更する)。

タイプコードを実行を選び、ソースPL/SQLコードとして以下を記述します。

declare
l_response clob;
begin
select json_object(
key 'd' value s.shop_name,
key 'v' value s.shop_code
) into l_response
from shp_shops s join shp_products p on s.shop_code = p.default_shop
where p.product_name = apex_application.g_x01;
apex_debug.info(l_response);
htp.p(l_response);
exception
when no_data_found then
htp.p('{}');
end;


レンダリング・ビューを開きます。

PRODUCT_NAME動的アクションを作成します。

識別名前onChange ProductNameタイミングはデフォルトでイベント変更選択タイプ対話グリッドShp OrdersPRODUCT_NAMEになります。


TRUEアクションとしてJavaScriptコードの実行を選択し、設定コードとして以下を記述します。

let grid = apex.region('orders').call('getViews','grid');
let model = grid.model;
let record = grid.getContextRecord(this.triggeringElement)[0];
let productName = $v(this.triggeringElement);
/*
* defaultShopsとして製品名と販売会社の組み合わせがキャッシュされていれば
* キャッシュを参照する。そうでない場合は、データベースに問い合わせる。
*/
if (defaultShops === undefined) {
apex.server.process(
"GET_DEFAULT_SHOP",
{
x01: productName
},
{
success: function( data ) {
if ( Object.keys(data).length ) {
model.setValue(record, "SHOP", data);
}
else
{
model.setValue(record, "SHOP", null);
}
}
}
)
}
else
{
model.setValue(record, "SHOP", defaultShops[productName]);
}
;
ページ・アイテムのAPIのsetValueは、引数として表示値(pDisplayValue)、値(pValue)を指定できますが、対話グリッドのsetValueは値(pValue)のみです。そのため、対話グリッドの選択リストやポップアップLOVへ値を設定するには、JSON形式{ d: "表示値", v: "値" } で渡します。


この状態でアプリケーションを実行すると、記事の先頭のGIF動画のように動作します。

とはいえ、対話グリッドに製品名を入力するたびに、ブラウザからデータベースへの問合せが発生するため、今ひとつ反応が良くありません。

ページが開いた時点で、製品名と販売会社の組み合わせを変数defaultShopsにキャッシュする機能を追加します。

プロセス・ビューを開き、AjaxコールバックとしてGET_DEFAULT_SHOPSを作成します。PL/SQLコードとして以下を記述します。

declare
l_response clob;
begin
/*
* 製品名と販売会社名, 販売会社コードのJSONを
* 連想配列として返す。
*/
select json_objectagg(
key p.product_name value
json_object(
key 'd' value s.shop_name,
key 'v' value s.shop_code
)
format json) into l_response
from shp_shops s join shp_products p on s.shop_code = p.default_shop;
-- apex_debug.info(l_response);
htp.p(l_response);
end;


レンダリング・ビューに戻り、ページ・プロパティJavaScriptページ・ロード時に実行に以下を記述します。

/*
* 製品と販売会社の組み合わせをキャッシュする。
*/
apex.server.process(
"GET_DEFAULT_SHOPS", {},
{
success: function( data ) {
defaultShops = data;
}
}
);


以上でアプリケーションは完成です。

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

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