Dynamic Enum values

Hi!

I tried to implement an Enum with dynamic values. By this, I mean an Enum those options are dependent on other values of the form.
There are already some topics about that, I read some of them, but I still have issues.

Here is what I did:
In uischema:

                                  {
                                     "type": "Control",
                                     "scope": "#/properties/name",
                                     "options": {
                                        "dynamicEnumDb": true
                                     }
                                  },

In schema:

            "name": {
               "type": "string"
            },

And I have a custom render for this field:

export const DatabaseDependency = (props: ControlProps & OwnPropsOfEnum) => {

  const ctx = useJsonForms();
  const wholeDataObject = ctx.core?.data;
  const allDatabaseNamesOptions = wholeDataObject.databases
    ?.map(
      (db: { name: any }) => {
        return { label: db.name, value: db.name } as EnumOption;
      }
    )
    ?? [];

  return (
    <MaterialEnumControl
      {...props}
      options={allDatabaseNamesOptions}
    />
  );
};


export const DatabaseDependencyTester = rankWith(
  3, //increase rank as needed
  and(
    scopeEndsWith('name'),
    optionIs('dynamicEnumDb', true)
  )

);

export default withJsonFormsControlProps(DatabaseDependency);

It works a little bit because the enum values are well rendered (see options={allDatabaseNamesOptions}) but the selection does not work.

When I try to select a value :

Uncaught Error: Objects are not valid as a React child (found: object with keys {name}). If you meant to render a collection of children, use an array instead.

With a already set value:

Must be string

Something is wrong between the string field and the options that are maps of value/labels.

Could you help me ?
Thanks a lot.

1 Like

Hi @ludovicmotte,

In general this looks pretty good. You should use the “unwrapped” MaterialEnumControl. Did you do so?

Oh yeah, thanks! I didn’t use “unwrapped” one. Now it is working. :grinning:

Another small issue :
When my other values are updated, the drop-down list is well updated.
But if the selected value is no more in the options, the list renders empty and the the selected value is still in the json,without errors.
Is is possible to remove the value and have an error ?

I hope I am clear.
Thanks.

Hi @ludovicmotte,

The cleanest solution is to have a custom renderer for your “other values” too. Whenever one is removed it should trigger some functionality which also removes the “selected” value of the “linked” property if necessary.

Alternatively you could listen to the data changes outside of JSON Forms and check for a “selected” value “linking” to a no longer existing value and remove it before handing the data back to JSON Forms.

An extremely hacky solution would be to check within the DatabaseDependency whether the selected value (i.e. the data prop) still exists and remove it from the data if not (via handleChange prop). However in general I would not recommend this approach as now your data update logic is tied to the UI and for example if the database dependency control is hidden via a rule the data would no longer be updated.