-
Notifications
You must be signed in to change notification settings - Fork 50
Description
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
FormRenderercomponent 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
applyRulesmethod I use constants forschemaanduiSchemainstead of props as I used to do before forFormcomponent. I had to do it this way because when I tried to get them from propsthis.props.jsonSchemaandthis.props.jsonLayoutrule 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;