Oracle JET CookbookにあるForEach Binding (Nested)をOracle APEXで実装してみます。
カテゴリが複数あり、それぞれのカテゴリに複数の製品が含まれています。カテゴリ単位の繰り返しは、ArraryTreeDataProviderをデータ・プロバイダとしたoj-bind-for-each要素で実装します。カテゴリに含まれている製品は、ArrayTreeDataProviderのメソッドgetChildDataProviderを呼び出して取得したデータ・プロバイダを使って表示します。
作成されたアプリケーションは以下のように動作します。
以下のクイックSQLのモデルより、表AG_CATEGORIESとAG_PRODUCTSを作成します。Oracle JET Cookbookでは、produce.jsonとしてサンプル・データが提供されていますが、少量なので手入力することにして、データ・ロードの実装は省きます。
# prefix: ag
categories
name vc80 /nn
products
name vc80 /nn
SQLの生成、SQLスクリプトを保存、レビューおよび実行を順次実施します。表の作成までを行い、アプリケーションは作成しません。
アプリケーション作成ウィザードを起動します。アプリケーションの名前はJET Bind For Each (Nested)とします。
ホーム・ページの編集をクリックし削除を実行したのち、ページの追加を行います
ページ名はFruits and Vegetables、形式は積上げを選択します。表(マスター表)としてAG_CATEGORIES、ディテール表としてAG_PRODUCTSを選択します。
以上でページの追加をクリックします。
その他の設定はせず、アプリケーションの作成を実行します。
アプリケーションが作成されます。今回はすべての機能をページFruits and Vegetablesに実装します。
ページ・デザイナでページFruits and Vegetablesを開きます。
Breadcrumb BarにあるJET Bind For Each (Nested)を削除します。JET Bind For Each (Nested)の上でコンテキスト・メニューを表示させ、削除を実行します。
積み上げ形式のマスター・ディテール編集画面は、マスター表AG_CATEGORIESとディテール表AG_PRODUCTSをデータ・ソースとした2つの対話グリッドから作られます。これらの対話グリッドのデータの整合性を保つため、対話グリッドにある保存のボタンを非表示にし、代わりに一度のクリックで表AG_CATEGORIESとAG_PRODUCTSの両方の保存を行なうボタンSAVE(保存)が作成されます。
このボタンSAVEの動作のアクションはページの送信です。ページの送信ではHTTPのPOSTリクエストがサーバーに発行され、ページの再ロードが行われます。Oracle JETで実装したリージョンはページを再ロードせずに更新されるようにしたいので、マスター・ディテールでの保存を少々変更します。
対話グリッドAg Productsを選択し、プロパティ・エディタの属性タブを開きます。
ツールバーのコントロールの保存ボタンにチェックを入れます。
プロセス・ビューを開きプロセスAG_PRODUCTS - 対話グリッド・データの保存を選択します。
サーバー側の条件のボタン押下時をSAVEから- 選択 -(つまり無指定)に戻します。
以上で表AG_PRODUCTSについては、ページの送信をせずにデータ操作ができるようになりました。
アプリケーションを実行し、サンプルのデータを入力します。必ずしもproduce.jsonと同じデータでなくても、アプリケーションの動作は確認できます。
識別のタイトルはFor Each (Nested)、タイプとして静的コンテンツを選択します。ソースのHTMLコードに以下を記述します。Oracle JET Cookbookのdemo.htmlとほぼ同じ内容です。
余計な装飾を除くため、外観のテンプレートとしてBlank with Attributes (No Grid)を選択します。
リージョンの描画に使うデータは、Ajaxコールバックを呼び出して取得します。
プロセス・ビューを開き、Ajaxコールバックにプロセスを作成します。
識別の名前はGET_DATA、タイプとしてコードを実行を選択します。ソースのPL/SQLコードとして以下を記述します。
以下のようなJSONのデータが返されます。
Oracle JET Cookbookのサンプルには属性childrenが含まれています。メソッドgetChildDataProviderが扱う属性のデフォルトがchildrenであるため、特別な指定が不要になります。今回はArrayTreeDataProviderのインスタンス作成時にchildrenAttributeとして属性productsを明示しているため、productsが含まれています。
[
{
"name": "Fruit",
"products": [
{
"name": "Orange"
},
{
"name": "Apple"
},
{
"name": "Banana"
}
]
},
{
"name": "Vegetable",
"products": [
{
"name": "Celery"
},
{
"name": "Spinach"
},
{
"name": "Corn"
}
]
}
]
レンダリング・ツリーに戻ります。
ページ・プロパティのJavaScriptのファイルURLに以下を記述します。
[require jet]
ファンクションおよびグローバル変数の宣言に以下を記述します。
var simple;
ページ・ロード時に実行に以下を記述します。
対話グリッドAg Productsでデータを変更し保存したときに、JETの表示を更新します。
対話グリッドAg Productsに動的アクションを作成します。
識別の名前はonSAVE Productsとします。タイミングのイベントとして保存[対話グリッド]を選択します。
TRUEアクションとしてJavaScriptコードの実行を選択し、設定のコードに以下の1行を記述します。
apex.actions.invoke("update-nested");
以上でアプリケーションは完成です。アプリケーションを実行すると、記事の先頭のGIF動画のように動作します。
今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/jet-bind-for-each-nested.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完