2023年9月5日火曜日

Oracle JETのoj-bind-for-each要素とArrayTreeDataProviderを使ってネストされた表示を実装する

Oracle JET CookbookにあるForEach Binding (Nested)をOracle APEXで実装してみます。

カテゴリが複数あり、それぞれのカテゴリに複数の製品が含まれています。カテゴリ単位の繰り返しは、ArraryTreeDataProviderをデータ・プロバイダとしたoj-bind-for-each要素で実装します。カテゴリに含まれている製品は、ArrayTreeDataProviderのメソッドgetChildDataProviderを呼び出して取得したデータ・プロバイダを使って表示します。

作成されたアプリケーションは以下のように動作します。


Oracle JET CookbookにあるForEach Binding (Nested)のページは以下です。


以下より実装手順を説明します。

以下のクイックSQLのモデルより、表AG_CATEGORIESAG_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と同じデータでなくても、アプリケーションの動作は確認できます。


Oracle JETによる描画を行なうリージョンを作成します。

識別タイトル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のアプリケーション作成の参考になれば幸いです。