2024年9月10日火曜日

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

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

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


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

表EBAJ_JSON_DATAの列CONTENTにJSON形式でデータを保存します。この列に保存するデータを入力するフォームを、表EBAJ_JSON_SCHEMASの列JSON_SCHEMA(JSON列の制約となるJSON Schema定義)と列UI_SCHEMA(UIの定義)から動的に生成します。列FORM_DATAはCONTENTに保存する初期値です。
# 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_DATAとEBAJ_JSON_SCHEMASを対象とした、フォーム付き対話モード・レポートのページが含まれています。

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


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


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

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


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

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


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

Live PlaygroundのSimpleとUI Optionsを対象に、同じ作業を行います。


Simple、UI 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_SCHEMAとP3_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のアプリケーション作成の参考になれば幸いです。

完