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

Customize fields to handle null values

Open moulinfr opened this issue 3 years ago • 4 comments

Prerequisites

Description

The JSON schema of the object I defined has a property that be be an array or null. I read the documentation and issues related to the support of the null value, so the "type" for this property in the JSON schema is set as "type": ["array", "null"]. However I have the following error when the value is actually null: TypeError: Cannot read properties of null (reading '0')

image

Patching the ArrayField.renderFixed array might be an option, but more generally to circumvent this issue I tried and failed to override the ArrayField as documented: if the value if null then display a message "Invalid null value" (using a <pre/> element f.e.), otherwise use the default ArrayField.

const NullableNumberField = function(props) {
	if (props.formData == null)
	{
		return <pre>Invalid value</pre>;
	}
	return <NumberField {...props}/>;
}
const NullableArrayField = function(props) {
	if (props.formData == null)
	{
		return <pre>Invalid value</pre>;
	}
	return <ArrayField {...props}/>;
}

const customFields = {NumberField: NullableNumberField, ArrayField: NullableArrayField, ObjectField: NullableObjectField};
form_element = 
	<Form schema={this.schema}
		id={'MyForm'}
		idPrefix={this.name.const}
		noValidate={true}
		formData={this.state.data}
		uiSchema={this.uiSchema}
		fields={customFields}
...

I still have the same error, and the React components tree is not what I expected; only the NullableObjectField (the top level custom field) is taken into account, any other custom fields are ignored.

image

Steps to Reproduce

  1. Implement the code as given in the description
  2. Set the value property to null
  3. Render the form.

Expected behavior

I expect that the "Invalid null value" is displayed is the value is actually null, otherwise render the array with the default template.

Actual behavior

Error TypeError: Cannot read properties of null (reading '0')

Version

rjsf/core: 3.2.1 rjsf/bootstrap-4: 3.2.1 react: 17.0.2 react-bootstrap: 1.6.4 react-dom: 17.0.2 react-jsonschema-form: 1.8.1

moulinfr avatar Jan 19 '22 09:01 moulinfr

I'm playing around with the same stuff and still have no solution.

I'm attempting to modify the json schema on the fly to match the actual json value, that is that say: instead of declaring multiple types for a property ["x", "null"], I am setting the type in the schema as "x" if the value is not null and "null" if the value is null. My testing is not comprehensive, still work to be done...

Quite ugly in fact, but might be a workaround?! Suggestions are welcome.

GuittonHubert avatar Jan 31 '22 10:01 GuittonHubert

I went through this issue by mainly patching the ArrayField.js in generateKeyedFormData() and renderFixedArray() to create a map based on the schema when the formData is null (no index available). For instance:

function generateKeyedFormData(formData, schema) {
    if (formData === null) {
		if (typeof schema.items === 'object') {
			return [];
		}
		else if (Array.isArray(schema.items)) {
			schema.items.map((item, index) => {
				return {
				  key: generateRowId(),
				  item: null
				};
			});
		}
		else {
			console.log('unsupported type', typeof schema.items);
		}
    }

  return !Array.isArray(formData)
    ? []
    : formData.map(item => {
        return {
          key: generateRowId(),
          item,
        };
      });
}

And

  renderFixedArray() {
...
    let itemSchemas = [];
    if (formData === null) {
        items = schema.items.map((item, index) => null);
        itemSchemas = schema.items.map((item, index) => item);
    }
    else  {
        itemSchemas = schema.items.map((item, index) =>
            retrieveSchema(item, rootSchema, formData[index])
        );
    }

Some more tweaks are spread through the code (ObjectField, I won't share here, unless I get some help to merge the code since I am a newbie in the github world for code management!

moulinfr avatar Feb 22 '22 14:02 moulinfr

With the v5 beta, maybe this is fixed, otherwise I'm open to helping you write a fix

heath-freenome avatar Aug 29 '22 23:08 heath-freenome

Hi Heath,

I will give a try to the v5 beta version; I'll come back to you within a few days. Thanks for your kind proposition.

moulinfr avatar Aug 31 '22 07:08 moulinfr

@moulinfr how did you patch it? we're in similar trouble, and i'm finding no way for a null (ideally would be undefined) default value to be respected for array fields that can be included or left out.

MartinCura avatar Oct 03 '23 12:10 MartinCura

A very hackishly hacky hack: added oneOf: [] to the properties, so that computeDefaults() is tricked into letting undefined as the value; still not perfect as now ArrayField's constructor ignores it and puts [] in its place 🙃 (const { formData = [] } = props;) but it gets us closer

MartinCura avatar Oct 03 '23 14:10 MartinCura