これは「react-jsonschema-formのカレンダー | Advent Calendar 2023 - Qiita」の18日目の記事です。
9日目の記事ではTemplateのカスタマイズとして
- BaseImputTemplate
- ObjectFieldTemplate
- FieldTemplate
をためしました。
ただ、 react-jsonschema-form (RJSF)には他にもTemplateが用意されています。
そこで今回は、Array系のTemplateをカスタマイズしてみます。
目次
環境
- react-jsonschema-form 5.15.0
- React 18.2.0
- React Router 6.20.1
Array系のデフォルトの表示
Templateをカスタマイズする前に、まずはArray系のデフォルトの表示を確認してみます。
以下では、 stringInput
と integerInput
のオブジェクトが要素であるArrayを定義しています。
import {RJSFSchema, UiSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; // MUI version import validator from "@rjsf/validator-ajv8"; export const DefaultArrayFieldsForm = () => { const schema: RJSFSchema = { title: "Default Array Fields", type: "object", description: "root description", properties: { arrayInput: { type: "array", title: "array input title", description: "array input description", items: { type: "object", title: "item title", description: "item description", properties: { stringInput: { type: "string", title: "string title", description: "string description" }, integerInput: { type: "integer", title: "integer title", description: "integer description" } } } } } } // 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> ) }
表示直後の状態は以下です。
続いて +
ボタンをクリックすることで、Arrayの要素が入力可能な表示となります。
また、-
ボタンで要素の削除が、 +
ボタンで要素の追加が、それぞれできるようになっています。
Array系のTemplateをカスタマイズ
続いてArray系のTemplateをカスタマイズしていきます。
なお、JSON Schemaは変更せず、Templateだけ差し替えます。
ArrayFieldTitleTemplate
まずは ArrayFieldTitleTemplate
をカスタマイズします。
https://rjsf-team.github.io/react-jsonschema-form/docs/advanced-customization/custom-templates#arrayfieldtitletemplate
ここでは title
を red
にしたTemplateを用意します。
import {ArrayFieldTitleProps, titleId} from "@rjsf/utils"; export const MyArrayFieldTitleTemplate = ({ title, idSchema }: ArrayFieldTitleProps) => { const id = titleId(idSchema) return ( <h1 id={id} style={{color: "red"}}>{title}</h1> ) }
Formでtemplatesを差し替えます。
<Form schema={schema} validator={validator} onSubmit={onSubmit} templates={{ ArrayFieldTitleTemplate: MyArrayFieldTitleTemplate }} />
表示すると、type="array"
の title
の文字色が red
に変わりました。
ArrayFieldDescriptionTemplate
続いて、 ArrayFieldDescriptionTemplate
をカスタマイズします。
https://rjsf-team.github.io/react-jsonschema-form/docs/advanced-customization/custom-templates#arrayfielddescriptiontemplate
ここでは description
を blue
にしたTemplateを用意します。
import {ArrayFieldDescriptionProps, descriptionId} from "@rjsf/utils"; export const MyArrayFieldDescriptionTemplate = ({ description, idSchema }: ArrayFieldDescriptionProps) => { const id = descriptionId(idSchema) return ( <p id={id} style={{color: "blue"}}>{description}</p> ) }
FormでTemplateを差し替えます。
<Form schema={schema} validator={validator} onSubmit={onSubmit} templates={{ ArrayFieldDescriptionTemplate: MyArrayFieldDescriptionTemplate }} />
表示すると、type="array"
の description
の文字色が blue
に差し替わりました。
ArrayFieldItemTemplate
カスタマイズ
次は ArrayFieldItemTemplate
をカスタマイズしてみます。
今回は darkkhaki
色の文字列 Field Item
を追加します。
import {ArrayFieldTemplateItemType} from "@rjsf/utils"; export const MyArrayFieldItemTemplate = (props: ArrayFieldTemplateItemType) => { return ( <> <div style={{color: "darkkhaki"}}>Field Item</div> <div>{children}</div> </> ) }
FormでTemplateを差し替えます。
<Form schema={schema} uiSchema={uiSchema} validator={validator} onSubmit={onSubmit} templates={{ ArrayFieldItemTemplate: MyArrayFieldItemTemplate }} />
表示して +
ボタンをクリックすると、各itemの一番先頭に文字列が追加されました。
hasToolbar propsとは何か
ところで、公式ドキュメントを見たところ、 hasToolbar
props の記載がありました。
hasToolbar
: A boolean value stating whether the array item has a toolbar.
しかし、 Toolbar
とは何かの説明が見当たりませんでした。
そこでソースコードを見たところ、以下の実装がありました。
https://github.com/rjsf-team/react-jsonschema-form/blob/v5.15.1/packages/core/src/components/fields/ArrayField.tsx#L843-L850
const has: { [key: string]: boolean } = { moveUp: orderable && canMoveUp, moveDown: orderable && canMoveDown, copy: copyable && canAdd, remove: removable && canRemove, toolbar: false, }; has.toolbar = Object.keys(has).some((key: keyof typeof has) => has[key]);
これより
- moveUp
- moveDown
- copy
- remove
の値により hasToolbar
の値が変わりそうでした。
ただ、上記のうち、 remove
がデフォルトでは常に true
なため、 hasToolbar
は常に true
となりそうでした。
Arrays | react-jsonschema-form
そこで、 uiSchemaで removable
を false
にして挙動をためしてみることにします。
まずはTemplateで、現在の各値をコンソールへ出力します。
import {ArrayFieldTemplateItemType} from "@rjsf/utils"; export const MyArrayFieldItemTemplate = (props: ArrayFieldTemplateItemType) => { const { hasMoveUp, hasMoveDown, hasRemove, hasToolbar, children, index } = props console.log("=========================>") console.log(index) console.log("hasMoveUp", hasMoveUp) console.log("hasMoveDown", hasMoveDown) console.log("hasRemove", hasRemove) console.log("hasToolbar", hasToolbar) return ( <> <div style={{color: "darkkhaki"}}>Field Item</div> <div>{children}</div> </> ) }
続いて、 uiSchema
にて removable = false
にします。
const uiSchema: UiSchema = { arrayInput: { 'ui:options': { removable: false, } } } const onSubmit = ({formData}, _event) => { console.log(formData) } return ( <div style={{width: '400px'}}> <Form schema={schema} uiSchema={uiSchema} validator={validator} onSubmit={onSubmit} templates={{ ArrayFieldItemTemplate: MyArrayFieldItemTemplate }} /> </div> )
動作確認をします。
+
ボタンを1回クリックした時のコンソールでは、関係する値がすべて false
になるため、 hasToolbar
も false
となることが分かりました。
続いて、 +
ボタンを2回クリックすると、 hasMoveDown
が true
になったため、 hasToolbar
も true
になりました。
ArrayFieldTemplate
次は ArrayFieldTemplate
をカスタマイズしてみます。
https://rjsf-team.github.io/react-jsonschema-form/docs/advanced-customization/custom-templates#arrayfieldtemplate
ここでは title
を orange
にしたTemplateを用意します。
import {ArrayFieldTemplateProps} from "@rjsf/utils"; export const MyArrayFieldTemplate = (props: ArrayFieldTemplateProps) => { const { title, items } = props return ( <> <div style={{color: "orange"}}>{title}</div> { items && items.map((item) => { return ( <div key={item.key}>{item.children}</div> ) }) } </> ) }
FormでTemplateを差し替えます。
<Form schema={schema} validator={validator} onSubmit={onSubmit} templates={{ ArrayFieldTemplate: MyArrayFieldTemplate }} />
表示すると、titleがorangeになりました。一方、入力項目は非表示になってしまいました。
続いて、入力項目を表示できないかと考え、Formに formData
を追加してみます。
<Form schema={schema} validator={validator} onSubmit={onSubmit} templates={{ ArrayFieldTemplate: MyArrayFieldTemplate }} formData={{ arrayInput: [ { stringInput: "foo", integerInput: 100 } ] }} />
すると、入力項目がformDataの値を伴って表示されました。
複数のArray系のTemplateを同時に利用する
最後に、複数のTempateを同時に利用したときにどのように表示されるかを確認します。
すべてのTempateを利用する
まずはすべてのTempateを利用した場合です。
<Form schema={schema} validator={validator} onSubmit={onSubmit} templates={{ ArrayFieldTemplate: MyArrayFieldTemplate, ArrayFieldItemTemplate: MyArrayFieldItemTemplate, ArrayFieldTitleTemplate: MyArrayFieldTitleTemplate, ArrayFieldDescriptionTemplate: MyArrayFieldDescriptionTemplate }} formData={{ arrayInput: [ { stringInput: "foo", integerInput: 100 } ] }} />
すると、 ArrayFieldTitleTemplate
の変更だけが反映されました。
ArrayFieldTitleTemplate以外を同時に利用する
では ArrayFieldTitleTemplate
を外すとどうなるかを確認します。
<Form schema={schema} validator={validator} onSubmit={onSubmit} templates={{ ArrayFieldItemTemplate: MyArrayFieldItemTemplate, ArrayFieldTitleTemplate: MyArrayFieldTitleTemplate, ArrayFieldDescriptionTemplate: MyArrayFieldDescriptionTemplate }} />
すると、指定したすべての内容が反映されました。
ソースコード
Githubにあげました。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023
今回のプルリクはこちら。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023/pull/16