これは「react-jsonschema-formのカレンダー | Advent Calendar 2023 - Qiita」の21日目の記事です。
JSON Schemaには additionalProperties
キーワードがあります。
Additional Properties | JSON Schema - object
これを使うことで、JSON Schemaにて定義していないプロパティをJSONに含めることができるか制御します。
さて、この additionalProperties
ですが、 react-jsonschema-form (RJSF) でも使えます。
Additional properties | Objects | react-jsonschema-form
そこで、RJSFで使った場合にどのように表示されるかを確認してみます。
目次
環境
- react-jsonschema-form 5.15.0
- React 18.2.0
- React Router 6.20.1
additionalPropertiesに色々な定義をしてみる
additionalProperties
に対して、色々定義してその表示を確認してみます。
string型の項目を定義した時の挙動
挙動確認
まずは、additionalPropertiesにstring型の項目を追加して、どのように表示されるか確認してみます。
JSON Schema的にはこんな感じです。
なお、additionalPropertiesでも
- title
- description
- default
の各値を定義できるため、ここでも定義して表示を確認してみます。
const schema: RJSFSchema = { title: "Additional String", type: "object", properties: { mainInput: { type: "string" } }, additionalProperties: { type: "string", title: "my title", description: "my description", default: "Default", } }
コンポーネントの全体像はこちら。
import {RJSFSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; import validator from "@rjsf/validator-ajv8"; export const AdditionalStringForm = () => { const schema: RJSFSchema = { ... } // JSON Schemaは省略 // onSubmitの引数の説明は以下 // https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props#onsubmit const onSubmit = ({formData}, _event) => { console.log(formData) } return ( <div style={{width: '400px'}}> <Form schema={schema} validator={validator} onSubmit={onSubmit} /> </div> ) }
次に表示してみます。初期表示は以下のようになりました。
mainInputの右下あたりにある +
ボタンをクリックすると、 additionalProperties
で定義したstring型の入力項目が表示されました。
- title
- description
が表示されています。
もう一度 +
をクリックすると、もう一つ入力項目が増えました。
この状態でsubmitボタンをクリックすると、additionalPropertiesで設定したキーと値が送信されました。
defaultで定義した値が表示されないというissueあり
先ほど見た通り、titleやdescriptionの各値が表示される一方で、defaultの値は表示されませんでした。
これについては以下にissueがあり、機能としては存在しないようでした。
Set default values for additionalProperties · Issue #3915 · rjsf-team/react-jsonschema-form
defaultの定義方法によっては、挙動がおかしくなるというissueあり
JSON Schemaのルート階層に default
キーワードを指定した場合、挙動がおかしくなるというissueがありました。
Object defaults for "additionalProperties" result in rows that cannot be deleted and have side effects when modified · Issue #3759 · rjsf-team/react-jsonschema-form
もしルート階層に default
を定義したい場合は気をつけたほうが良さそうです。
object型の項目を定義した時の挙動
次に additionalProperties に object型の項目を定義してみます。
単一のプロパティを持つobject型の場合
まずは単一のプロパティの表示を確認します。
用意したJSON Schemaはこんな感じです。
なお、他の部分はstring型のときと同じなため、省略します。
const schema: RJSFSchema = { title: "Additional Object Only String", type: "object", properties: { mainInput: { type: "string" } }, additionalProperties: { type: "object", properties: { additionalString: { type: "string", title: "additional title", description: "additional description", default: "string default" } } } }
この状態で表示し、 +
ボタンをクリックすると以下の表示となりました。
string型と異なり、titleとdescriptionに加え、defaultで指定した値も表示されています。
もう一度 +
ボタンをクリックした後submitしたところ、additionalPropertiesの値は送信されていました。
複数のプロパティを持つobject型の場合
続いて、複数のプロパティを持つobject型の表示を確認してみます。
JSON Schemaはこちら。
const schema: RJSFSchema = { title: "Additional Object", type: "object", properties: { mainInput: { type: "string" } }, additionalProperties: { type: "object", title: "my title", description: "my description", default: "Default", properties: { additionalString: { type: "string", title: "string title", description: "string description", default: "string default" }, additionalInteger: { type: "integer", title: "integer title", description: "integer description", default: 10 } } } }
+
ボタンを押してadditionalPropertiesを表示したところ、以下となりました。
こちらも +
ボタンをもう一度クリックしてsubmitしたところ、各項目のデータが送信されました。
JSON Schemaがサポートしていない型を定義した時の挙動
RJSFでは、JSON Schemaがサポートしていない時に表示するテンプレートなどが定義されています。
- UnsupportedFieldTemplate | Custom Templates | react-jsonschema-form
- https://github.com/rjsf-team/react-jsonschema-form/blob/v5.15.1/packages/core/src/components/templates/UnsupportedField.tsx#L9
では、JSON Schemaがサポートしていない型をadditionalPropertiesで定義したときにどのような表示となるかを確認してみます。
用意したJSON Schemaは以下です。
なお、以下の定義を使う場合は型エラーが発生した状態となります。
const schema: RJSFSchema = { title: "Additional Unsupported Type", type: "object", properties: { mainInput: { type: "string" } }, additionalProperties: { type: "unsupported" } }
初期表示後 +
ボタンを押すと、以下の表示となりました。
また、この状態でsubmitするとバリデーションエラーとなり、以下のメッセージが表示されました。
schema is invalid: data/additionalProperties/type must be equal to one of the allowed values, data/additionalProperties/type must be array, data/additionalProperties/type must match a schema in anyOf, data/properties/newKey/type must be equal to one of the allowed values, data/properties/newKey/type must be array, data/properties/newKey/type must match a schema in anyOf
uiSchemaでhidden定義をした時の挙動
RJFSでは、uiSchemaで hidden
widgetを定義することで、定義した項目をhiddenにできます。
Hidden widgets | Widgets | react-jsonschema-form
そこで、additionalPropertiesの項目をhiddenにした場合にどのような表示になるかためしてみます。
まずはJSON Schemaを定義します。
今回は hiddenString
をhidden項目とします。
また、title・description・defaultも定義し、それらの項目がどう表示されるかを確認します。
const schema: RJSFSchema = { title: "Additional Hidden", type: "object", properties: { mainInput: { type: "string" } }, additionalProperties: { type: "object", title: "my title", description: "my description", default: "Default", properties: { hiddenString: { type: "string", title: "string title", description: "string description", default: "string default" } } } }
続いて、uiSchemaにhidden項目の定義を行います。
なお、公式ドキュメントに
You can also define uiSchema options for additionalProperties by setting the additionalProperties attribute in the uiSchema.
https://rjsf-team.github.io/react-jsonschema-form/docs/json-schema/objects/#additional-properties
とあるように、 additionalProperties
プロパティの下に、hiddenとしたい項目のキーを指定します。
const uiSchema: UiSchema = { additionalProperties: { hiddenString: { 'ui:widget': 'hidden' } } }
あとはFormのpropsに schema
と uiSchema
を渡します。
<Form schema={schema} uiSchema={uiSchema} validator={validator} onSubmit={onSubmit} />
では実際に表示してみます。
+
ボタンをクリックすると、titleとdescriptionだけが表示されました。
さらに +
ボタンをクリックすると、もう1セット、titleとdescriptionが表示されました。
この状態でsubmitすると、hiddenのdefault値が送信されました。
ソースコード
Githubにあげました。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023
今回のプルリクはこちら。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023/pull/19