How to use findUISchema

Hello,

I’d like to use findUISchema in a custom angular material control to be able to input the rendererProps of the JsonFormsOutle like it’s done in TableRenderer for instance.

The idea is to be able to manage a dictionary. I’d like to be able to add and remove entries (done) but also to edit the value of an entry (problematic).

Here is an example of the JSON Schema:

{
“type”: “object”,
“properties”: {
“someprop”: {
“type”: “object”,
“properties”: {
“dictionary”: {
“type”: “array”,
“title”: “A beautiful dictionary”,
“items”: {
“type”: “object”,
“properties”: {
“key”: {
“type”: “string”,
“minLength”: 1
},
“value”: {
“type”: “string”,
“minLength”: 1
}
},
“required”: [
“key”,
“value”
],
“additionalProperties”: false
},
“minItems”: 1,
“additionalItems”: false
}
},
“additionalProperties”: false
}
}
}

And the UI Schema looks like this:

{
“type”: “Dictionary”,
“scope”: “#/properties/someprop/properties/dictionary”
}

In my renderer, for each item of my data, I try to generate the renderer properties using this snipet:

getRendererProps(index: number): OwnPropsOfRenderer {
const { schema, uischemas, scopedSchema, uischema } = this;
const controlElement = uischema as ControlElement;
const path = Paths.compose(this.propsPath, ${index}.value);
const rendererUischema = findUISchema(
uischemas,
scopedSchema,
uischema.scope,
path,
“Control”,
null,
schema
);
return {
schema,
path,
uischema: rendererUischema,
};
}

I tried many combinaisons for the arguments of findUISchema but I cannot get it to work…

Could you please explain to me how to use this function, the context and different arguments?

Hi @JBBianchi! Your use case is the same as in the array-layout renderer: You want to determine the UI schema for your array items.

Therefore I would assume that this should give you the UI schema you want:

    const uischema = findUISchema(
      this.uischemas,
      this.scopedSchema,
      this.uischema.scope,
      this.propsPath,
      undefined,
      this.uischema
    )

In general findUISchema expects:

  • uischemas the UI Schema registry (most users are not using that feature)
  • schema the JSON Schema for which to find a UI Schema. In your case the scopedSchema should already point at the items, i.e. it should be
{
  type: 'object',
  properties: {
    key: {
      type: 'string',
      minLength: 1
    },
    value: {
      type: 'string',
      minLength: 1
    }
  },
  required: ['key', 'value'],
  additionalProperties: false
}
  • schemaPath. This is used to query the UI Schema registry uischemas to find a registered UI Schema for this path. Probably not relevant for your use case.
  • path. The data path for the current schema. Also only used for the UI Schema registry uischemas and therefore probably not relevant for your use case.
  • fallbackLayoutType (optional). The type of the generated UI Schema. As the name indicates this should definitely be some layout element into which the generated controls are placed. In your case this should probably be VerticalLayout (default) or HorizontalLayout or Group
  • control (optional). The UI Schema for the JSON Schema array. Used to check the UI Schema options object
  • rootSchema (optional). The root schema of the form. Used for special resolving cases. Probably not needed in your case.

Thanks for your reply @sdirix

Unfortunatly, I wasn’t able to point to the right path. I’m probably turning around the good setup but couldn’t find it. I reproduced my use case here: github[DOT]com/JBBianchi/jsonforms-angular-seed/blob/master/src/app/dictionary.renderer.ts#L106 Would you be so kind to have a look and point me in the right direction?

Hi @JBBianchi, did you try what I suggested in my last answer? The code you linked still uses a custom path entry instead of the propsPath prop.

I did, same kind of outcome. I updated the repo so it reflects your suggestion.

I’m pretty sure it’s a little something I’m doing wrong somewhere but I couldn’t figure what/where.

For the returned path,

    Paths.compose(this.propsPath, ``${index}``)`

is probably correct, just not for findUiSchema. I’m comparing your code with the already existing Material Array Layout renderer.

Note that the setReadOnly unsetReadOnly methods are deprecated. You should just hand over the enabled state of your renderer to your children.

I feel like it’s getting closer but still not good:

getRendererProps(index: number): OwnPropsOfRenderer {
    const { schema, uischemas, scopedSchema, uischema, propsPath } = this;
    const path = Paths.compose(this.propsPath, `${index}`);
    const rendererUischema = findUISchema(
      uischemas,
      scopedSchema,
      uischema.scope,
      propsPath,
      undefined,
      this.uischema
    );
    return {
      schema: scopedSchema,
      path,
      uischema: rendererUischema,
    };
  }

When using this, I end up with 2 controls, for key and value. I tried to change path to const path = Paths.compose(this.propsPath, ``${index}.value``); or to change the path in findUISchema but I cannot find a way to only target value

Edit:

With a dirty workaround, I can manage to do what I want but it doesn’t feel right:

    return {
      schema: scopedSchema,
      path,
      uischema: (rendererUischema as any).elements[1],
    };

(see dictionary.renderer@b34e1a2)

Edit2:
In the meanwhile, for my use-case, I went with the table.renderer approach meaning creating the control instead of finding it. See dictionary.renderer@4bd139e

Well yes, with the auto generated ui schema you’ll always have one Control per property. So in your case that’s key and value. If that’s not what you want then there is definitely no need to call findUISchema but you can simply create the ui schema yourself, as you now did.