Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional object with required fields in react-jsonschema-form #675

Closed
2 tasks done
davidMcneil opened this issue Aug 22, 2017 · 19 comments · Fixed by #3436
Closed
2 tasks done

Optional object with required fields in react-jsonschema-form #675

davidMcneil opened this issue Aug 22, 2017 · 19 comments · Fixed by #3436

Comments

@davidMcneil
Copy link
Contributor

davidMcneil commented Aug 22, 2017

Prerequisites

  • I have read the documentation;
  • In the case of a bug report, I understand that providing a SSCCE example is tremendously useful to the maintainers.

Description

Given a json schema like the one below, the react-jsonschema-form validator essentially requires both shipping_address and billing_address even though the billing_address is not listed as required. This is because the address type requires all three of its properties. How can I make the billing_address optional?

{
  "definitions": {
    "address": {
      "type": "object",
      "properties": {
        "street_address": {
          "type": "string"
        },
        "city": {
          "type": "string"
        },
        "state": {
          "type": "string"
        }
      },
      "required": [
        "street_address",
        "city",
        "state"
      ]
    }
  },
  "type": "object",
  "properties": {
    "billing_address": {
      "title": "Billing address",
      "$ref": "#/definitions/address"
    },
    "shipping_address": {
      "title": "Shipping address",
      "$ref": "#/definitions/address"
    }
  },
  "required": [
    "shipping_address"
  ]
}

Steps to Reproduce

Here is a link to the react-jsonschema-form playground.

Expected behavior

It seems that react-jsonschema-form should simply no submit billing_address if not all of its address properties are filled in.

Actual behavior

The form validator prevents the form from being submitted.

Version

0.49.0

@n1k0
Copy link
Collaborator

n1k0 commented Aug 23, 2017

I'm surprised with this behavior too, and the jsonschema lib is not at fault here as validating raw data works just as expected. We may be altering the schema in some way, which is bad.

@gdbassett
Copy link

Has this fix been merged? If not, is there a target for merging it? My org has started using the plugin but are getting lots of invalid data due to turning off validation due to required fields within non-required objects.

@davidMcneil
Copy link
Contributor Author

This has not been merged. There are a few outstanding issues that need to be worked through. You can see the discussion at the merge request (#682). Unfortunately, I do not have time to cleanup the issues that need to be worked through in the immediate future. I am sure that if these issues were addressed the fix would be quickly merged.

@christianblos
Copy link

Any news on this one?

@christianblos
Copy link

christianblos commented May 9, 2018

If someone else comes across this issue and can not wait for a real fix, you can extend the Form component and override the validate function. Here's an example in Typescript:

class ReactJsonSchemaForm<T> extends Form<T> {
    validate(formData: any, schema: any) {
        formData = removeOptionalEmptyValues(formData, this.props.schema);
        //@ts-ignore
        return super.validate(formData, schema);
    }
}

removeOptionalEmptyValues() is a function I created to remove objects from formData if their values are empty. Don't forget to call removeOptionalEmptyValues() on onSubmit as well.

@epicfaace
Copy link
Member

Playground link

Part of the problem here is that 1) when all the shipping address fields are set to be blank, shipping_address is set to {} in the formData -- shipping_address does not disappear altogether.
And given this schema:

{
  "definitions": {
    "address": {
      "type": "object",
      "properties": {
        "street_address": {
          "type": "string"
        },
        "city": {
          "type": "string"
        },
        "state": {
          "type": "string"
        }
      },
      "required": [
        "street_address",
        "city",
        "state"
      ]
    }
  },
  "type": "object",
  "properties": {
    "billing_address": {
      "title": "Billing address",
      "$ref": "#/definitions/address"
    },
    "shipping_address": {
      "title": "Shipping address",
      "$ref": "#/definitions/address"
    }
  },
  "required": [
    "billing_address"
  ]
}

The following schema is not valid:

{
  "billing_address": {
    "street_address": "asd",
    "city": "Babel",
    "state": "Neverland"
  },
  "shipping_address": {},
  "tree": {
    "name": "root",
    "children": [
      {
        "name": "leaf"
      }
    ]
  }
}

Whereas only the following schema is valid:

{
  "billing_address": {
    "street_address": "asd",
    "city": "Babel",
    "state": "Neverland"
  },
  "tree": {
    "name": "root",
    "children": [
      {
        "name": "leaf"
      }
    ]
  }
}

And the second problem is the same as mentioned above; even when the key shipping_address is removed from the formData, the fields still highlight as red / required.

@psehgal
Copy link

psehgal commented Jan 2, 2020

Any updates with this? I am running into the same issue.

@afernandez8
Copy link

afernandez8 commented Apr 22, 2020

Hello, any updates with this? I am running into the same issue. And i can't fix with this: #675 (comment)

@vonElfvin
Copy link

vonElfvin commented Oct 9, 2020

A workaround I went with:

const formatInitialFormData = (
  initialFormData: Record<string, unknown>,
  schema: JSONSchema7,
): Record<string, unknown> => {
  const properties = schema.properties!
  const formData = { ...initialFormData }
  Object.entries(properties).forEach((property) => {
    const key = property[0]
    const value = property[1] as JSONSchema7
    formData[key] = initialFormData[key] ?? value?.default ?? undefined
  })
  return formData
}

Consumed by:

  const [formData, setFormData] = useState(formatInitialFormData(initialFormData ?? {}, schema))

  ...

  <Form
     formData={formData}
   ...
  />

It is not perfect for all use cases but does the trick for me.

@daverck
Copy link

daverck commented Aug 17, 2021

Hello, any updates with this? I am running into the same issue. And i can't fix with this: #675 (comment)

Try with the following :

export class ReactJSONSchemaForm<T> extends Form<T> {

  constructor(props: any){
    super(props)
    let oldValidate = this.validate;
    this.validate = (
      formData: T,
      schema?: FormProps<T>['schema'],
      additionalMetaSchemas?: FormProps<T>['additionalMetaSchemas'],
      customFormats?: FormProps<T>['customFormats'],
      ): {errors: AjvError[], errorSchema: ErrorSchema} => {  
        
        let fixedFormData = trimEmptyValues(formData)
        return oldValidate.call(this, fixedFormData, schema)
      }
  }
}

@iamkhalidbashir
Copy link

Running into this issue as well

@vorobievik
Copy link

Any updates with this? I am running into the same issue

@Rozamo
Copy link
Contributor

Rozamo commented Dec 13, 2022

Till this gets fixed from the code side you can try making some changes to your schema if it fits your requirement. You can remove the required property from the address definition and use JSON Schema dependencies whenever referenced. The following schema works for me. It's a bit tedious but does the job.

{
    "definitions":
    {
        "address":
        {
            "type": "object",
            "properties":
            {
                "street_address":
                {
                    "type": "string"
                },
                "city":
                {
                    "type": "string"
                },
                "state":
                {
                    "type": "string"
                }
            }
        }
    },
    "type": "object",
    "properties":
    {
        "billing_address":
        {
            "title": "Billing address",
            "$ref": "#/definitions/address",
            "dependencies":
            {
                "street_address":
                {
                    "required":
                    [
                        "city",
                        "state"
                    ]
                },
                "city":
                {
                    "required":
                    [
                        "street_address",
                        "state"
                    ]
                },
                "state":
                {
                    "required":
                    [
                        "city",
                        "street_address"
                    ]
                }
            }
        },
        "shipping_address":
        {
            "title": "Shipping address",
            "$ref": "#/definitions/address",
            "required":
            [
                "street_address",
                "city",
                "state"
            ]
        }
    },
    "required":
    [
        "shipping_address"
    ]
}

heath-freenome added a commit to heath-freenome/react-jsonschema-form that referenced this issue Feb 6, 2023
fixes: rjsf-team#675 by reverting the `allowEmptyObject` change on Form
- In `@rjsf/utils`, reverted the `allowEmptyObject` change as follows:
  - Removed the `allowEmptyObject` changes made to `getDefaultFormState`, `computeDefault` and `maybeAddDefaultToObject`
  - Updated `maybeAddDefaultToObject` to take the list of required fields and allow adding an empty object if the field is required
  - Updated the `SchemaUtilsType` to revert the `allowEmptyObject` change
  - Updated the tests to remove testing `allowEmptyObject` and to add testing the `required` field state
- In `@rjsf/core, removed the passing of `allowEmptyObject` to `getDefaultFormState`
  - Updated the tests for form to include the test case from rjsf-team#675
- In `utility-functions` documentation, removed the documentation of `allowEmptyObject`
- Updated the `CHANGELOG.md` accordingly
heath-freenome added a commit that referenced this issue Feb 6, 2023
fixes: #675 by reverting the `allowEmptyObject` change on Form
- In `@rjsf/utils`, reverted the `allowEmptyObject` change as follows:
  - Removed the `allowEmptyObject` changes made to `getDefaultFormState`, `computeDefault` and `maybeAddDefaultToObject`
  - Updated `maybeAddDefaultToObject` to take the list of required fields and allow adding an empty object if the field is required
  - Updated the `SchemaUtilsType` to revert the `allowEmptyObject` change
  - Updated the tests to remove testing `allowEmptyObject` and to add testing the `required` field state
- In `@rjsf/core, removed the passing of `allowEmptyObject` to `getDefaultFormState`
  - Updated the tests for form to include the test case from #675
- In `utility-functions` documentation, removed the documentation of `allowEmptyObject`
- Updated the `CHANGELOG.md` accordingly
@nickgros nickgros mentioned this issue Feb 10, 2023
1 task
@bluisana
Copy link

6 years later and it looks like this bug still exists. I have a large amount of complex schemas that can't be modified using "depencies" or other conditionals. It is expected behavior of a schema that objects properties are not required if the object itself isn't required. I am testing this with the following simply schema. Is there any fix for this that I am missing that doesn't involve changing the actual schemas?

schema: { type: 'object', properties: { person: { type: 'object', properties: { id: { type: 'string', }, name: { type: 'string', }, }, required: ['name'], }, }, example: '{}', }

@heath-freenome
Copy link
Member

heath-freenome commented Mar 29, 2023

@bluisana can you explain what is not working properly in detailed steps within this playground. As far as I can tell this issue has been fixed in 5.x

@bluisana
Copy link

bluisana commented Mar 31, 2023

Hello @heath-freenome, This works perfectly in the playground example but doesn't work in my application. After tons of experimenting I finally figured out what is going on. This functionality only works when you have noHtml5Validate = false. If you have noHtml5Validate set to true all inputs are required regardless of the required state of their parents.

@heath-freenome
Copy link
Member

heath-freenome commented Mar 31, 2023

@bluisana So it seems we probably need to add a switch to enable/disable the noHtml5Validate in the playground and then we would see this issue show up? Please create a feature request for this. And also, maybe a bug for your use case

@fdecollibus
Copy link

I am facing the same issue

@heath-freenome
Copy link
Member

@fdecollibus Are you using the latest 5.x release and set noHtml5Validate to false on the Form?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.