Stefan Dobreさんによるこちらの記事 How to dynamically compute Interactive Grid Columns in #orclAPEX 20.2 の紹介です。
記事に記載されている実装を行うことで、理解してみました。色々と応用ができますし、同様の処理を大量の動的アクションで実装していた方は、ずっと分かりやすく書き換えることができるでしょう。
この機能は、Oracle APEXを20.2以降よりサポートされています。
以下が確認作業の順番です。
- 表とアプリケーションの作成
- CSVファイルのロード
- 計算によって導出される列を、対話グリッドのSQLに追加
- 対話グリッド上で、列の計算を行うコードを追加
1から2までは準備作業になります。Oracle APEXによるアプリケーション作成について経験のある方にとっては、冗長かもしれません。
表とアプリケーションの作成
サンプルの受注一覧のデータより、商品(PRODUCT_NAME)の価格(PRICE)と数量(QUANTITY)より、売り上げ(REVENUE)を計算します。売り上げは
REVENUE = PRICE * QUANTITY
として計算するため、表の列には含みません。
クイックSQLに与える設定は、以下とします。
# prefix: dmt
orders
product_name vc255 /nn
price num
quantity num
SQLワークショップよりクイックSQLを開き、左側に上記のモデルを入力します。
SQLの生成、SQLスクリプトを保存、レビューおよび実行を順次実行します。
SQLスクリプトが開きます。DDLの変更は不要なので、そのまま実行します。確認画面が開くので、即時実行をクリックします。
表DMT_ORDERSが作成されます。続けてアプリケーション作成を実行します。
アプリケーション作成ウィザードが起動します。
作成するアプリケーションの名前は対話グリッドの計算とします。デフォルトで追加されているページをすべて削除し(編集をクリックして削除を実行)、代わりにページの追加をクリックして対話グリッドを追加します。
対話グリッドのページ名も対話グリッドの計算とします。表またはビュー、編集を許可を選択し、表またはビューとして表DMT_ORDERSを選択します。
ページの追加をクリックします。
以上の設定を行い、アプリケーションの作成を実行します。
アプリケーションが作成されます。今回の作業はページ番号1の対話グリッドの計算のページに対して実施します。
CSVファイルのロード
ロードするCSVファイルを、以下よりダウンロードします。
https://apex.oracle.com/pls/apex/japancommunity/r/simcontents/download?id=SampleOrders.csv
次にSQLワークショップのユーティリティより、データ・ワークショップを開きます。データのロードをクリックして開きます。
ファイルのアップロード(デフォルトで選択されています)より、ファイルの選択をクリックして、先ほどダウンロードしたSampleOrders.csvを選択します。
データのロードを行う前に、構成をクリックします。
受注番号のマップ先としてID(Number)、製品はPRODUCT_NAME(Varchar2)、単価はPRICE(Number)、数量はQUANTITY(Number)を指定します。単価と数量にはグループ・セパレータとして,(カンマ)、小数点文字として.(ピリオド)を指定します。私がテストしたときは、小数点文字のデフォルトが,(カンマ)になっていたので、設定変更は必須です。
表DMT_ORDERSに含まれる4つの列をマップして、変更の保存を行います。
103行のデータがロードされていれば、ロードは成功です。続けてアプリケーションの作成を実行します。
列REVENUEをSQLに追加
対話グリッドのページをページ・デザイナで開き、対話グリッドのリージョンを左ペインより選択します。ソースのタイプをSQL問合せに切り替え、SQL問合せを以下の列REVENUEを追加したものに更新します。
select ID,
PRODUCT_NAME,
PRICE,
QUANTITY,
NVL(PRICE,0) * NVL(QUANTITY,0) as REVENUE
from DMT_ORDERS
列REVENUEが追加されます。元記事によると、今回のソリューションは編集可能な列にのみ適用可能なので、タイプを表示のみに設定することは不可です。しかし、列REVENUEは計算された結果でありユーザーからの入力は禁止したいので、外観のCSSクラスにis-readonlyを指定します。また、データベースのアップデート操作に含まれないよう問合せのみをONにします。
変更を保存して、ページを実行します。
この状態で列Price、Quantityを変更して、保存をクリックすると列Revenueに計算結果が反映されることが確認できます。
次に、保存をクリックせず、PriceやQuantityを変更するとすぐにRevenueが更新される実装を行います。
対話グリッド上の列の計算
Oracle APEX 20.2から利用可能になったcalcValueとdependsOnの機能を使用します。
列REVENUEのプロパティである詳細の列初期化JavaScriptファンクションに以下を記述します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function(options){ | |
options.defaultGridColumnOptions = { | |
dependsOn: ['PRICE', 'QUANTITY'], | |
calcValue: function(argsArray, model, record){ | |
const price = parseInt(model.getValue(record, 'PRICE').replaceAll(",","") || 0); | |
const quantity = parseInt(model.getValue(record, 'QUANTITY').replaceAll(",","") || 0); | |
if(isNaN(price) || isNaN(quantity)){ | |
return 'error'; | |
} else { | |
return price * quantity; | |
} | |
} | |
}; | |
return options; | |
} |
dependsOnとして、この列REVENUEが依存している列を指定します。REVENUEはPRICEとQUANTITYの積なので、dependsOnはPRICEとQUANTITYになります。
dependsOnで指定された列、PRICEまたはQUANTITYが変更されたときに呼び出されるファンクションをcalcValueとして記述します。戻り値が列REVENUEの値になります。
以上のコードを設定して、期待した動作になるか確認してみましょう。列REVENUEを計算しているJavaScriptのコードの部分については、理解が難しいところはないかと思います。
おまけ:書式マスクについて
数値列である列PRICEとQUANTITYに以下のような書式マスクの設定がされていると、3桁ごとに区切り文字として,(カンマ)が含まれます。
999G999G999G999G999G999G999G999G999G990
このままではparseInt()で適切な整数として変換されないので、replaceAll(",","")でカンマを取り除いています。
対話グリッドの計算結果としても,(カンマ)を含めるには、Intl.NumberFormatを使って以下のように記述することで対応できます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function(options){ | |
const formatter = Intl.NumberFormat("ja-JP"); | |
options.defaultGridColumnOptions = { | |
dependsOn: ['PRICE', 'QUANTITY'], | |
calcValue: function(argsArray, model, record){ | |
const price = parseInt(model.getValue(record, 'PRICE').replaceAll(",","") || 0); | |
const quantity = parseInt(model.getValue(record, 'QUANTITY').replaceAll(",","") || 0); | |
if(isNaN(price) || isNaN(quantity)){ | |
return 'error'; | |
} else { | |
return formatter.format(price * quantity); | |
} | |
} | |
}; | |
return options; | |
} |
以上で、対話グリッドの列の計算方法の紹介は終了です。
今回作成したアプリケーションのエクスポートを以下に置きました。https://github.com/ujnak/apexapps/blob/master/exports/calcvalue-interactive-grids.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完