I am working to create dependent select controls (e.g. state/city, select state, get list of cities). In this example, when the state is changed, I want to clear any selections made on the city control. I have created an onChange handler that uses handleChange to clear the values. When invoked on the primary control, the JSONForms state of the dependent control is properly updated but the control itself continues to display the previously selected values. I have also tried to use dispatch(Actions.update(controlName, () => []))
without success.
In the below example I have two controls, a ‘primary_control’ and a ‘dependent_control’. When the primary is modified, I want to clear the selections of the dependent.
What is the proper way to properly update the other control?
import {
JsonSchema,
ControlProps,
RankedTester,
rankWith,
schemaMatches,
and,
isEnumControl,
OwnPropsOfEnum,
EnumOption,
Actions,
} from '@jsonforms/core';
import { JsonFormsStateContext, withJsonFormsContext, withJsonFormsEnumProps } from '@jsonforms/react';
import { Autocomplete, Grid, TextField, Typography } from '@mui/material';
import { useEffect, useState } from 'react';
type JsonSchemaWithDependency = JsonSchema & { use_dependent_control: boolean };
interface WithContext {
ctx: JsonFormsStateContext,
props: ControlProps & OwnPropsOfEnum
}
export const SimpleControl = (props: WithContext) => {
const schema = props.props.schema as JsonSchemaWithDependency;
const coreOptions = props.props.options ? props.props.options : []
const [options, setOptions] = useState<EnumOption[]>(coreOptions);
const {
id,
label,
handleChange,
path,
} = props.props;
const {
dispatch
} = props.ctx
useEffect(() => {
// "dynamically" set the options of this control e.g. from an API.
setOptions([{ "label": "Foo", "value": "1" }, { "label": "Bar", "value": "2" }])
}, []);
const onChange = (_ev: any, newValues: any) => {
// update this control
handleChange(path, newValues);
if ('primary_control' === path) {
// This updates the JSONForms state but the MUI control is not updated
handleChange('dependent_control', []);
// This also updated the JSONForms state but leaves the control unchanged.
// if (dispatch) {
// dispatch(Actions.update('dependent_control', () => []))
// }
}
}
return (
<Grid container>
<Grid item xs={12}>
<Autocomplete
id={id}
autoComplete
fullWidth
disableCloseOnSelect
freeSolo={false}
isOptionEqualToValue={(option, value) => option.value === value.value}
getOptionLabel={(option) => option.value}
options={options ? options : []}
onChange={onChange}
multiple={true}
renderInput={(params) => (
<TextField {...params} label={label} variant="outlined" />
)}
/>
</Grid>
</Grid>
);
};
export const simpleControlTester: RankedTester = rankWith(
5,
and(
isEnumControl,
schemaMatches((schema) => schema.hasOwnProperty('use_dependent_control')),
)
);
export default withJsonFormsEnumProps(withJsonFormsContext(SimpleControl));
{
"type": "object",
"properties": {
"primary_control": {
"title": "Primary Control",
"type": "string",
"enum": ["East", "West", "North", "South"],
"use_dependent_control": true
},
"dependent_control": {
"title": "Dependent Control",
"type": "string",
"enum": ["Never", "Daily", "Weekly", "Monthly"],
"use_dependent_control": true
}
}
}
{
"type": "VerticalLayout",
"elements": [
{
"type": "Control",
"scope": "#/properties/primary_control"
},
{
"type": "Control",
"scope": "#/properties/dependent_control"
}
]
}