react-jsonschema-form
react-jsonschema-form copied to clipboard
Render my custom components depending on the input type
Prerequisites
- [X] I have read the documentation
What theme are you using?
mui
What is your question?
If type is number I want to simply render the input that rjsf provides and just tweak some details (for example provide a translated label).
But if it's a checkbox I want to render a MUI Switch (by default rjsf renders a checkbox). I'm working on something like this (WiP, not working):
const CustomBaseInputTemplate = (props: BaseInputTemplateProps) => {
const { type, label, schema, options, title, ...rest } = props
const inputProps = { ...rest, ...getInputProps(schema, type, options) }
const { BaseInputTemplate } = Templates
switch (inputProps.type) {
case 'number':
return (
<BaseInputTemplate
{...props}
label={translate(translationKey)}
id={schema.title}
variant='outlined'
/>
)
case 'checkbox':
return (
<Switch //MUI Switch component
{...props}
id={schema.title}
/>
)
default:
return <></>
}
}
<Form
schema={schema}
validator={validator}
templates={{
BaseInputTemplate: CustomBaseInputTemplate
}}
/>
Is this approach correct?
Currently returning <BaseInputTemplate /> does not work. I followed #3481 suggestion, but it returns an error:
JSX element type 'BaseInputTemplate' does not have any construct or call signatures.ts(2604)
'BaseInputTemplate' cannot be used as a JSX component.
Its type 'ComponentType<BaseInputTemplateProps<any, RJSFSchema, any>> | undefined' is not a valid JSX element type.
Type 'undefined' is not assignable to type 'ElementType'.ts(2786)
@arnaumanyosa You are probably better off either overriding the CheckboxWidget or creating a custom field for the switch behavior and then using the uiSchema to make the fields you want to be switches to use the custom field. Let me know if you have any other questions. If not, feel free to close this issue
@heath-freenome Thanks for the quick response. I got it for the Switch. But still I'm struggling with two things:
-
How I use 'ui:widget' in uiSchema to override more than one widget? Because it does not accept an array or an object
-
Which approach would you follow to translate all the label of the different components (Textfield, Switch). I read on the docs that there is an include localization feature, but I'm using another lib (React I18nify). So basically somewhere I need to call a translate function where I pass a key.
-
All my fields have default values. If it's read-only I want to render just text, not a disabled component. Is there a way to do this generically for all the fields?
Thanks again for all your time and efforts!
@arnaumanyosa Have you read the docs on translateString? As for making things read-only with rendered text, you will have to implement your own custom component or field to do this, sorry. That's how I implemented it in my world. Since most of the fields you deal with are probably text, you could wrap the BaseInputTemplate to render things differently by checking the readonly flag.
Thanks again for the replay @heath-freenome
Have you read the docs on translateString?
Yes, but if I understand correctly, with translateString it's only possible to translate library strings? (not the label of my inputs)?
Beside of this, as I mentioned I already have a i18n library in place, it's cumbersome to have to maintain another (and the translation files, etc)
As for making things read-only with rendered text, you will have to implement your own custom component or field to do this
I made my custom widgets and fields in a similar way (btw, also including the translation for the labels). Here is an approximated code:
const CustomMuiSwitch = function (props: WidgetProps) {
return props.readonly ? (
translate('form.label')
) : (
<FormGroup>
<FormControlLabel
control={
<Switch
checked={props.value}
onChange={(event) => props.onChange(event.target.checked)}
/>
}
label={translate('form.label)}
/>
</FormGroup>
)
}
const CustomMuiNumberTextField = (props: FieldProps) => {
return props.readonly ? (
translate('form.label')
) : (
<TextField
type='number'
size='small'
required={props.required}
label={translate('form.label')}
variant='outlined'
value={String(props.formData)}
onChange={(event) => props.onChange(parseInt(event.target.value))}
InputProps={{
inputProps: {
min: props.schema.minimum,
max: props.schema.maximum
}
}}
/>
)
}
const customWidgets: RegistryWidgetsType = {
CheckboxWidget: CustomMuiSwitch,
}
const customFields: RegistryFieldsType = {
NumberField: CustomMuiNumberTextField
}