rjsf-team / react-jsonschema-form

A React component for building Web forms from JSON Schema.
https://rjsf-team.github.io/react-jsonschema-form/
Apache License 2.0
14.33k stars 2.19k forks source link

Antd Steps component not working #4330

Open Sam-Simplifed opened 4 weeks ago

Sam-Simplifed commented 4 weeks ago

Prerequisites

What theme are you using?

antd

Version

5.x

Current Behavior

When a step component value is required in rjsf . If a user submit the form without filling the required question then getting error { "name": "required", "property": "Little interest or pleasure in doing things", "message": "This field is required.", "params": { "missingProperty": "Little interest or pleasure in doing things" }, "stack": "must have required property 'Little interest or pleasure in doing things'", "schemaPath": "#/required" } while other antd components are working fine because other components have a id and name prop and if the user submit form without answering the required question then the scroll move to that question and below that "Field is required" message shows up. But in case of Step component, the above error shows in the console after debugging found that the Steps component does not have id or name props.

import { useState } from 'react';
import { Steps, Grid } from 'antd';

const { useBreakpoint } = Grid;

const SliderField = (props: any) => {
  const screens = useBreakpoint();
  const index = props.options.enumOptions.findIndex((option) => option.value === props.value) ?? '';
  const [current, setCurrent] = useState<any>(index);
  const onChange = (step: number) => {
    const { value } = props.options.enumOptions[step];
    setCurrent(step);
    props.onChange(value);
  };

  return (
    <>
      <Steps
        className="select-steps"
        size="small"
        responsive
        direction={screens['xl'] ? (props.options.enumOptions.length > 4 ? 'vertical' : 'horizontal') : 'vertical'}
        progressDot={true}
        current={current}
        onChange={onChange}
        items={props.options.enumOptions.map((result) => {
          return { title: result.value, disabled: props.disabled };
        })}
      />
    </>
  );
};

export default SliderField;
import React, { useEffect } from 'react';
import Form from '@rjsf/antd';
import useSchemaBuilder from '../../rjsfForm/useSchemaBuilder';
import { Button } from 'antd';
import { customizeValidator } from '@rjsf/validator-ajv8';

const FormLayout = ({
  haveSections,
  submitForm,
  formSchema,
  hideSubmit,
  updateFormValue,
  sectionName,
  onFormChange,
  submitBtnTxt,
  ...rest
}: any) => {
  const [schema, uiSchema, schemaBuilder] = useSchemaBuilder();

  useEffect(() => {
    schemaBuilder(formSchema);
  }, []);

  uiSchema['ui:options'] = {
    submitButtonOptions: {
      norender: hideSubmit,
    },
  };

  function transformErrors(errors: any, m) {
    console.log({ errors });

    return errors.map((error: any) => {
      if (error.name === 'required') {
        error.message = 'This field is required.';
      }
      if (error.message === 'must be equal to one of the allowed values') {
        error.message = 'This field is required.';
      }
      if (error.name === 'minItems') {
        error.message = 'Please select at least one option.';
      }

      return error;
    });
  }

  const customFormats = {
    'phone-us': /\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{4}$/,
  };

  const validator = customizeValidator({ customFormats });

  return (
    <>
      <Form
        {...rest}
        omitExtraData
        focusOnFirstError
        onChange={(data) => {
          if (haveSections) {
            if (!Object.keys(data.formData)?.length) {
              return;
            }

            onFormChange(sectionName, data);
          }
        }}
        className="exam-form preview-form-wraper"
        onSubmit={(data) => {
          if (haveSections) {
            updateFormValue(sectionName, data);
          } else {
            updateFormValue(data);
          }
        }}
        schema={schema ?? {}}
        uiSchema={uiSchema}
        showErrorList={false}
        validator={validator}
        liveValidate={!rest.disabled}
        transformErrors={transformErrors}
      >
        {!hideSubmit && (
          <div className="d-flex justify-content-end">
            <Button htmlType="submit" type="primary" size="large">
              {submitBtnTxt ?? 'Submit'}
            </Button>
          </div>
        )}
      </Form>
    </>
  );
};

export default React.memo(FormLayout, (oldProps, newProps) => {
  return oldProps.formSchema.questions.length === newProps.formSchema.questions.length;
});

Expected Behavior

If a user try to submit the form without filling the required fields. Then it should no show the error on the console.

No response

Steps To Reproduce

No response

Environment

- OS: macOS 
- Node: 20.10.0
- npm: 10.2.3

Anything else?

No response

heath-freenome commented 3 weeks ago

@Sam-Simplifed Great work in debugging! Since you know what and where the issue is, are you willing to step up and provide what seems to be a simple fix for it?

Sam-Simplifed commented 3 weeks ago

@heath-freenome As we can not add the name or id pros to Steps component. But we can create a custom widget that wraps the Antd Steps component and adds unique id or name attributes. This allows the validation system to identify the step properly.

heath-freenome commented 3 weeks ago

@Sam-Simplifed we would love a PR that will add these to the base implementation