2024年9月10日火曜日

react-jsonschema-formを使ってJSON列を扱うフォームを生成する

react-jsonschema-formを組み込んで、データベースのJSON列向けのフォームを自動生成してみます。

作成するアプリケーションは以下のように動作します。フォームを生成するJSON Schemaを選択し、APEXのフォーム(ドロワーとして実装)を開きます。開いたフォームは、選択したJSON Schemaから生成されたフォームを含みます。以下のGIF動画では、JSON SchemaとしてSimpleUI Optionsのどちらかを選んでいて(react-jsonschema-formのLive Playgroundから拝借しています)、選択によってフォームに表示される項目が変わります。JSON Formの領域に含まれている項目は、JSON形式でひとつの列に保存されます。


クイックSQLの以下のモデルを元に、表EBAJ_JSON_DATAEBAJ_JSON_SCHEMASを作成します。

EBAJ_JSON_DATAの列CONTENTにJSON形式でデータを保存します。この列に保存するデータを入力するフォームを、表EBAJ_JSON_SCHEMASの列JSON_SCHEMA(JSON列の制約となるJSON Schema定義)と列UI_SCHEMA(UIの定義)から動的に生成します。列FORM_DATACONTENTに保存する初期値です。
# prefix: ebaj
json_data
    title vc80 /nn
    content json
    schema_id num /fk json_schemas

json_schemas
    title vc80 /nn
    json_schema json
    ui_schema json
    form_data json
SQLワークショップユーティリティよりクイックSQLを開き、上記のモデルで表を作成します。今回は表の作成後、アプリケーションの作成まで続けて実行します。

レビューおよび実行をクリックします。


SQLスクリプトスクリプト・エディタが開きます。スクリプト名を設定し、実行をクリックします。


即時実行をクリックします。


エラーがなくDDLの実行が完了していることを確認します。

アプリケーションの作成をクリックします。


確認画面が表示されるので、再度アプリケーションの作成をクリックします。


アプリケーション作成ウィザードが開きます。アプリケーションの名前JSON Formとします。表EBAJ_JSON_DATAEBAJ_JSON_SCHEMASを対象とした、フォーム付き対話モード・レポートのページが含まれています。

アプリケーションの作成をクリックします。


アプリケーションが作成されます。


アプリケーションを実行し、フォームを生成する元となるJSONスキーマを登録します。

Json Schemasのページを開きます。


JSONスキーマはreact-jsonschemas-formのLive Playgroundからコピーします。

今回はSimpleUI Optionsについて、APEXアプリケーションに登録します。SimpleまたはUI Optionsを選択したときに表示されるJSONSchemaUISchemaおよびformDataをAPEXのフォームにコピペします。


Json Schemas作成をクリックし、フォームを開きます。Json SchemaUI SchemaおよびForm Dataを入力し、作成をクリックします。

Live PlaygroundSimpleUI Optionsを対象に、同じ作業を行います。


SimpleUI Optionsの双方とも、uiSchemaにてSubmitボタンを描画する設定になっています。SubmitボタンはAPEX側で作成するため、JSONのフォームでは不要です。SimpleではuiSchemaに以下の一行を含めます。

  "ui:submitButtonOptions": { "norender": true },

UI Optionsにはui:submitButtonOptionsの設定が含まれています。norenderの指定をfalseからtrueに変更しておきます。

Json Schemasのレポートに、登録されたスキーマSimpleとUI Optionsの2行が表示されます。


このスキーマより、表EBAJ_JSON_DATAの列CONTENTを対象としたフォームを生成します。

ページ・デザイナで、表EBAJ_JSON_DATAの対話モード・レポートのページ(ページ番号2)を開きます。このページにある作成ボタンおよびレポート行にある編集アイコンをクリックすると、表EBAJ_JSON_DATAを編集するフォームが開きます。そのフォーム上に、react-jsonschema-formを使ったフォームを組み込みます。

編集フォームを開く際に、列CONTENTのフォームを生成するJSON Schemaを選択するページ・アイテムを作成します。

識別名前P2_SCHEMA_IDタイプ選択リストラベルSchemaとします。設定選択時のページ・アクションとして値のリダイレクトと設定を選択します。

LOVタイプ共有コンポーネントを選択し、LOVとしてEBAJ_JSON_SCHEMAS.TITLEを選択します。このLOVはアプリケーション作成の元となったDDLに参照制約が含まれているため、自動的に生成されました。追加値の表示オフNULL値の表示オンとし、NULL表示値として- Select JSON Schema -を入力します。

値の選択を変えるたびに警告が表示されるのを抑止するため、詳細保存されていない変更の警告無視にします。


ボタン作成をクリックしたときに、ページ・アイテムP2_SCHEMA_IDとして選択した値をフォームに渡すようにします。

ボタンCREATEを選択し、動作ターゲットを開きます。


アイテムの設定名前としてP3_SCHEMA_IDとして&P2_SCHEMA_ID.を追加し、OKをクリックします。


以上で、react-jsonschema-formを組み込む準備ができました。

これから、フォームのページ(ページ番号3)に、react-jsonschema-formを組み込みます。

ページ・デザイナでページ番号3のフォームのページを開きます。

JSON Schemaを保持するページ・アイテムP3_JSON_SCHEMAを作成します。タイプ非表示です。セッション・ステートデータ型CLOBストレージリクエストごと(メモリーのみ)を選択します。


UI Schemaを保持するページ・アイテムP3_UI_SCHEMAを作成します。設定内容はP3_JSON_SCHEMAと同じです。


ページ・アイテムP3_JSON_SCHEMAP3_UI_SCHEMAおよびP3_CONTENTを初期化するプロセスを作成します。

レンダリング前ヘッダーの前にプロセスを作成します。識別名前Initialize JSON Formとします。タイプコードを実行です。

ソースPL/SQLコードとして以下を記述します。
declare
    l_form_data clob;
begin
    select
        json_schema, ui_schema, form_data
    into
        :P3_JSON_SCHEMA, :P3_UI_SCHEMA, l_form_data
    from ebaj_json_schemas
    where id = :P3_SCHEMA_ID;
    if :P3_CONTENT is null then
        :P3_CONTENT := l_form_data;
    end if;
end;

ページ・プロパティHTMLヘッダーに、Reactとreact-jsonschema-formを参照するためのimportmapを設定します。
<script type="importmap">
    {
        "imports": {
            "react": "https://cdn.jsdelivr.net/npm/react@18.3.1/+esm",
            "react-dom": "https://cdn.jsdelivr.net/npm/react-dom@18.3.1/+esm",
            "@rjsf/core": "https://cdn.jsdelivr.net/npm/@rjsf/core@5.20.1/+esm",
            "@rjsf/utils": "https://cdn.jsdelivr.net/npm/@rjsf/utils@5.20.1/+esm",
            "@rjsf/validator-ajv8": "https://cdn.jsdelivr.net/npm/@rjsf/validator-ajv8@5.20.1/+esm",
            "@rjsf/bootstrap-4": "https://cdn.jsdelivr.net/npm/@rjsf/bootstrap-4@5.20.1/+esm"
        }
    }
</script>
JavaScriptファイルURLにBabelをロードするURLを設定します。

https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js


CONTENT(ページ・アイテムP3_CONTENT)に値を設定するフォームとなるリージョンを作成します。

識別名前JSON Formタイプ静的コンテンツです。ソースHTMLコードとして以下を記述します。



react-jsonschema-formのテーマとして、依存の少ないbootstrap-4を選んでいます。

CSSのファイルURLとして、以下のURLを指定します。

https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css


以上で一通り動作するアプリケーションは完成です。ページ・アイテムP3_CONTENTは実際にはタイプ非表示にすべきですが、JSON Formのフィールドを操作したときに値が変更されることを目視するために、そのままにしておきます。

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

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

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