react-jsonschema-form icon indicating copy to clipboard operation
react-jsonschema-form copied to clipboard

Render my custom components depending on the input type

Open arnaumanyosa opened this issue 1 year ago • 1 comments

Prerequisites

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 avatar Oct 18 '24 09:10 arnaumanyosa

@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 avatar Oct 18 '24 19:10 heath-freenome

@heath-freenome Thanks for the quick response. I got it for the Switch. But still I'm struggling with two things:

  1. How I use 'ui:widget' in uiSchema to override more than one widget? Because it does not accept an array or an object

  2. 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.

  3. 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 avatar Oct 20 '24 20:10 arnaumanyosa

@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.

heath-freenome avatar Oct 21 '24 17:10 heath-freenome

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
}

arnaumanyosa avatar Oct 28 '24 12:10 arnaumanyosa