Label for array items selected from oneOfs (with ReactRenderer + MaterialRenderer)

My Json schema contains an array, whose items are strings that can be selected from a oneOf.

Example (also on Stackblitz):

{
  $schema: 'http://json-schema.org/schema#',
  $id: 'OneOfInArrayExample',
  type: 'object',
  properties: {
    myArray: {
      type: 'array',
      items: {
        type: 'string',
        oneOf: [
          { const: 'A', title: 'Nice title describing A' },
          { const: 'B', title: 'Nice title describing B' },
        ],
      },
    },
  },
}

By default, JsonForms renders this as follows:

where I have expanded the first item. Due to the lack of a label, a collapsed item tells you nothing.

I want either the const or the title value in the label of each item (preferrably the title).

How can this be expressed in a JsonForms UI schema? The elementLabelProp seems not to be helpful here.

Rendering using checkboxes (with uniqueItems) does not work for me since in my actual project the array of selectable values in oneOf is quite long.

Thanks in advance

Hi!

This case is not that well supported off the shelf.

At the moment the generic array layout renderer wins versus the table renderer. This is why the collapsible sections are rendered which is way too overkill for a single input. Also the generic layout renderer is meant for complex objects, not for simple values, therefore there is currently no way to refer to that simple value via the elementLabelProp. If if it would be possible: The elementLabelProp can only refer to the actual values in the data, it does not enable to list the associated title of the JSON Schema.

I consider this an error that the table renderer is not used here. The table renderer supports the oneOf-as-used-for-enum case, so it should really be used here. Until this is fixed in JSON Forms you can just do so manually, e.g. like this:

import {
  materialRenderers,
  MaterialArrayControlRenderer,
} from '@jsonforms/material-renderers';
import { and, uiTypeIs, schemaMatches, rankWith } from '@jsonforms/core';

const useTableRendererForOneOfsEntry = {
  renderer: MaterialArrayControlRenderer,
  tester: rankWith(
    100,
    and(
      uiTypeIs('Control'),
      schemaMatches((schema) => {
        if (schema.type && schema.type !== 'array') {
          return false;
        }
        if (
          schema.items &&
          typeof schema.items === 'object' &&
          !Array.isArray(schema.items)
        ) {
          return (
            schema.items.oneOf &&
            schema.items.oneOf.every((oneOf) => oneOf.const !== undefined)
          );
        }
        return false;
      })
    )
  ),
};
const renderers = [...materialRenderers, useTableRendererForOneOfsEntry];

This renders a much more useable UI:

1 Like

Opened MaterialTableRenderer should be invoked on `oneOf`s · Issue #2081 · eclipsesource/jsonforms · GitHub