2022年6月16日木曜日

沢山のページ・アイテムの値を移動先のページに受け渡す

 ページを遷移する際に、元のページに沢山あるページ・アイテムの値を次のページに渡す良い方法は、という相談がありました。

多分、コレクション(APEX_COLLECTION)を介してページ・アイテムの値を受け渡すのが、一番容易な方法でしょう。

以下、簡単なサンプルを実装してみました。

遷移先のページは、元ページをコピーして作成したので見た目がほとんど同じですが、ページ遷移をした後のページ・アイテムに同じ値が設定されていることが確認できます。

空のアプリケーション(名前ページ・アイテムの受け渡しとしました)を作成します。

ホーム・ページにタイプ静的コンテンツのリージョンを作成し、ページ・アイテムを3つ作成します。ページ・アイテムP1_STRINGはタイプがテキスト・フィールドP1_NUMBERはタイプが数値フィールドP1_DATEはタイプが日付ピッカーです。


このページをコピーして、移動先のページを作成します。

ページ番号とします。ページ・アイテムの名前のプレフィックスがP1_からP2_へ変更されます。


元のページから次のページへ、移動するためのボタンを作成します。

識別名前B_NEXTラベル次のページへ移動とします。動作アクションにはページの送信を選択します。


ボタンをクリックしてページを移動する場合、アクションとしてこのアプリケーションのページにリダイレクトを選択することが多いです。引き渡す値は、リンク・ビルダー・ターゲットアイテムの設定に定義します。

例えば以下のような設定になります。今回の例では、アクションとしてページの送信を選択するため、この設定は行いません。


このアクションを選択していると、ボタンを押した時にHTTPのGETリクエストが発行されます。ページが表示されるときに、そのときのP1_STRING、P1_NUMBER、P1_DATEの値を使って、移動先のURLが生成されます。ページが生成されるときにページ・アイテムの値が未設定であれば、生成されるリンクの値も未設定になります。

/ords/r/apexdev/transfer-page-items/target?p2_date=&p2_number=&p2_string=&session=111004570014402&cs=1ZxL6vkecnEat5QZYcmAy0EmIigHF1xtyOpjy50O1RGOFltrXUeyikviuqiFBtxiXdk25iSCsglj6SwGiwjxrVQ

ページが表示された後の変更は、ボタンに含まれている宛先のURLには反映されません。

アクションとしてこのアプリケーションのページにリダイレクトが想定しているのは、表の一覧のレポートから、データを変更するためのフォームを開くといった、主キーを引数として別ページを開くようなページの遷移です。

フォームのページから、別のページのフォームに遷移する場合は、ボタンのアクションページの送信を選択します。アクションがページの送信の場合は、HTTPのPOSTリクエストが発行されます。ページに含まれるすべてのページ・アイテムの値はPOSTリクエストのコンテンツとして、サーバーに送信されます。そのためサーバーは、ボタンを押した時点のページ・アイテムの値を受信します。

以下より、APEXコレクションを使ったページ・アイテムの値の受け渡しを実装します。

最初にページ・アイテムの受け渡しに使用するAPEXコレクションの名前を、アプリケーション定義置換として定義します。

置換文字列としてG_TPI_COLLECTION_NAME置換値TRANFERRED_PAGEITEMSとします。

コレクション名はアプリケーションの各所で参照されることがあるので、一箇所で変更できるようにしておきます。また、コレクション名を間違うと原因を見つけるのが大変なので、直書きはせず常にバインド変数を介して指定します。


共有コンポーネントアプリケーション・アイテムとしてG_TPI_SEQ_IDを作成します。このアプリケーション・アイテムは、コレクションのSEQ_IDを保存するために使用します。

セッション開始時にコレクションを初期化します。

共有コンポーネントアプリケーション・プロセスを作成します。プロセス・ポイント新規インスタンス(新規セッション)開始時、実行するコードは以下になります。APEX_COLLECTION.CREATE_OR_TRUNCATE_COLLECTIONを呼び出します。
begin
    apex_collection.create_or_truncate_collection(
        p_collection_name => :G_TPI_COLLECTION_NAME
    );
end;

ページ・アイテムを送信するページに、ページ・プロセスを作成します。

実行するコードは以下になります。APEX_COLLECTION.ADD_MEMBERを呼び出します。受け渡すページ・アイテムの数だけ、指定する引数を追加します。コレクションにはVARCHAR2、NUMBER、DATE型などで値を保存することができます。ページ・アイテムが保持しているデータは基本的に文字列ですが、コレクションに保存する際に型を適切に選択するとTO_CHARやTO_NUMBERファンクションの呼び出しが不要になります。

ページの遷移はブランチで行います。
begin
     :G_TPI_SEQ_ID := apex_collection.add_member(
          p_collection_name => :G_TPI_COLLECTION_NAME
          , p_c001 => :P1_STRING
          , p_n001 => :P1_NUMBER
          , p_d001 => :P1_DATE
      );
end;

ページ・アイテムを受信するページに、ページ・プロセスを作成します。

プロセスはページのレンダリング前ヘッダーの前に実行します。APEX_COLLECTIONSビューを検索し、値を取り出します。

実行するコードは以下になります。
begin
    select c001, n001, d001 
    into :P2_STRING, :P2_NUMBER, :P2_DATE
    from apex_collections
    where 1=1
        and collection_name = :G_TPI_COLLECTION_NAME
        and seq_id = :G_TPI_SEQ_ID
    ;
end;

APEXコレクションを使用したページ・アイテムの値の受け渡し方法の実装は以上になります。

今回作成したAPEXアプリケーションにエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/transfer-page-items.sql

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