react-jsonschema-form-conditionals
react-jsonschema-form-conditionals copied to clipboard
help wanted: Am I using this lib correctly with my react component?
Hello.
I use react-jsonschema-form
and need to extend it with more complex conditions, so, I decided to use this extension.
Below is my FormRenderer
component where I used to render Form
component where FormWithConditionals
is now.
I struggle with two things:
- In order to use it I have to define a const within my
FormRenderer
component as shown in the example. So, I do this:FormWithConditionals = applyRules(this.jsonSchema, this.jsonLayout, this.rules_simplified, Engine)(Form);
Then I render it like this:
<this.FormWithConditionals
formData={this.state.formData}
className="form-renderer"
noHtml5Validate
liveValidate
onChange={this.onChange}
FieldTemplate={FieldTemplate}
ArrayFieldTemplate={ArrayTemplate}
showErrorList={false}
formContext={{ formError: this.state.error }}
// uiSchema={this.props.jsonLayout}
// schema={this.props.jsonSchema}
onSubmit={this.props.showSubmitButton ? this.onSubmit : undefined}
onError={this.onError}
widgets={Widgets}
fields={Fields}
omitExtraData
liveOmit
transformErrors={this.suppressEmptyOptionalObjectError}
validate={this.validateEmptyRequiredObjectFields}
>
It looks weird to me: I need to use <**this.**FormWithConditionals>
in order to use it. I didn't find a way to have it in a separate file as a standalone component/wrapper and then being imported and used because I don't know how to provide the rest of regular Form props to it (onChange, liveValidation and so on..). My attempt below obviously fails because when I try to use it in FormRenderer
where Form
used to be it complains about all the rest of usual Form
parameters. Does it mean that defining it as a const and then using with <this.FormWithConditionals
is the only way to do it?
interface IFormWithConditionalsProps {
jsonSchema: ISchema;
jsonLayout: ILayout;
rules: any;
}
const FormWithConditionals = (props: IFormWithConditionalsProps) => applyRules(props.jsonSchema, props.jsonLayout, props.rules, Engine)(Form);
export default FormWithConditionals
- My second issue is that with the approach above I cannot use shcema and layout from props. Notice that when I create the component in
applyRules
method I use constants forschema
anduiSchema
instead of props as I used to do before forForm
component. I had to do it this way because when I tried to get them from propsthis.props.jsonSchema
andthis.props.jsonLayout
rule engine failed at validation step. It seems that at initial rendering they are provided with empty values, and rule engine fails at rules validation because it cannot find the field which I refer in rule's remove event. When I use hardcoded constants instead of props with the same values as in props - it works becuse everything is provided at once. Could you suggest any solution for this?
Full code:
import React from 'react';
import FieldTemplate from './field-template';
import ArrayTemplate from './array-template';
import { MuiPickersUtilsProvider } from '@material-ui/pickers';
import DateFnsUtils from '@date-io/date-fns';
import { Button, Grid } from '@material-ui/core';
import { ArrowForward } from '@material-ui/icons';
import { ILayout, ISchema } from 'app/modules/content-management/spaces/space/form-wizard/form-tab/form-builder/model/schema-model';
import Widgets from 'app/modules/spaces/forms/form-renderer/fields/index';
import Fields from 'app/modules/spaces/forms/form-renderer/fields/custom-object-field/index';
import { excludeFields, orderFormData } from 'app/shared/util/form-data';
import FormHeader from 'app/modules/spaces/forms/form-header';
import {
flattenDependencies,
isGroupField
} from 'app/modules/content-management/spaces/space/form-wizard/form-tab/form-builder/model/field-model-util';
import { FormModel } from 'app/modules/content-management/spaces/space/form-wizard/form-tab/form-builder/model/form-model';
import { FieldModel } from 'app/modules/content-management/spaces/space/form-wizard/form-tab/form-builder/model/abstract/field-model';
import Form from 'react-jsonschema-form';
import applyRules from 'react-jsonschema-form-conditionals';
import Engine from 'json-rules-engine-simplified';
import FormWithConditionals from './form-with-conditionals';
export interface IFormRendererProps {
jsonSchema: ISchema;
jsonLayout: ILayout;
showSubmitButton: boolean;
spaceAlias: string;
formAlias: string;
isPreview?: boolean;
formData: object;
onSubmit(data): void;
}
export interface IFormRendererState {
error: boolean;
formData: object;
sending: boolean;
}
interface IReactJsonSchemaError {
name: string;
params: {
missingProperty?: string;
};
property: string;
}
class FormRenderer extends React.Component<IFormRendererProps, IFormRendererState> {
rules_simplified = [{
conditions: {
'bd9d6a94-19cc-4bfd-8836-00e75dd445ad': {equal: 'aaa'}
},
event: {
type: "remove",
params: {
field: '3c9a0dd9-97af-4dc8-b83d-0380c958f3f1'
},
}
}];
jsonSchema = {
"type" : "object",
"required" : [ "bd9d6a94-19cc-4bfd-8836-00e75dd445ad" ],
"properties" : {
"bd9d6a94-19cc-4bfd-8836-00e75dd445ad" : {
"title" : "text field",
"type" : "string"
},
"3c9a0dd9-97af-4dc8-b83d-0380c958f3f1" : {
"title" : "text field2",
"type" : "string"
}
}
};
jsonLayout = {
"ui:order" : [ "bd9d6a94-19cc-4bfd-8836-00e75dd445ad", "3c9a0dd9-97af-4dc8-b83d-0380c958f3f1" ],
"bd9d6a94-19cc-4bfd-8836-00e75dd445ad" : {
"ui:widget" : "text",
"ui:disabled" : false,
"ui:options" : { }
},
"3c9a0dd9-97af-4dc8-b83d-0380c958f3f1" : {
"ui:widget" : "text",
"ui:disabled" : false,
"ui:options" : { }
}
};
FormWithConditionals = applyRules(this.jsonSchema, this.jsonLayout, this.rules_simplified, Engine)(Form);
constructor(props: IFormRendererProps) {
super(props);
this.state = {
error: false,
sending: false,
formData: props.formData ?? {}
};
}
onError = () => {
this.setState({ error: true });
};
onChange = data => this.setState({ formData: data.formData });
onSubmit = async data => {
this.setState({ sending: true });
await this.props.onSubmit(orderFormData(excludeFields(data.uiSchema, data.formData), data.uiSchema['ui:order']));
};
render() {
const isPreview = this.props.isPreview ?? false;
return (
<>
{isPreview ? null : (
<FormHeader formData={this.state.formData} formAlias={this.props.formAlias} spaceAlias={this.props.spaceAlias} />
)}
<Grid container>
<Grid item xs={1} lg={3} />
<Grid item xs={isPreview ? 12 : 10} lg={isPreview ? 12 : 6}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<this.FormWithConditionals
formData={this.state.formData}
className="form-renderer"
noHtml5Validate
liveValidate
onChange={this.onChange}
FieldTemplate={FieldTemplate}
ArrayFieldTemplate={ArrayTemplate}
showErrorList={false}
formContext={{ formError: this.state.error }}
// uiSchema={this.props.jsonLayout}
// schema={this.props.jsonSchema}
onSubmit={this.props.showSubmitButton ? this.onSubmit : undefined}
onError={this.onError}
widgets={Widgets}
fields={Fields}
omitExtraData
liveOmit
>
{this.props.showSubmitButton ? (
<Button aria-label="Submit" className="form-renderer-submit-btn" type="submit" disabled={this.state.sending}>
Send
<ArrowForward fontSize="large" className="ml-2" />
</Button>
) : (
<br />
)}
</this.FormWithConditionals>
</MuiPickersUtilsProvider>
</Grid>
</Grid>
</>
);
}
}
export default FormRenderer;