Error doesn't show up in custom renderer

I have crated a custom renderer and have a schema that defines an object. Within that object there is a string property for which I added format to validate it. Now i can see the errors in the common JsonFroms component on the onChange functions but can’t see them in my custom renderer. The renderer is used based on a property isTextField that is defined in the schema.
Schema:

JsonForms “wrapper” where the new format is created

Custom renderer

For anyone wondering.
I ended up using the context provided by useJsonForms().
You can get the errors from there and then filter based on the instancePath.
Although this approach may not be optimal because if I wanted to do other validations on my params I would need to filter the errors for each case.

Hi @Icenwharth,

The onChange from JsonForms has nothing to do with the onChange of TextInput. They just share the same name:

  • The onChange of JsonForms is emitted, whenever there is a change within JsonForms and returns the whole data object and all AJV errors.

  • The onChange of Material UI for TextInput just gives you a change event for the input. At that point of time JsonForms does not yet know anything about the change and therefore couldn’t validate it.

The integration with JsonForms is accomplished via the handleChange method. The handleChange applies the data change at the right place (i.e. the path) of the form-wide data object and triggers a validation pass etc. This will then trigger a re-render where you get the new local data and the errors relevant to your data handed over.

Looking at the listed schema and code it seems that you modeled a postalCode object within the schema but you want to handle the whole object via a single textual input? It would help if you could post more of the code, especially how your tester and binding invocation look like.

If this is what you actually want to do (i.e. use a string renderer for the whole object and showing the errors of the whole object) then you need to manually filter the errors out of the JSON Forms form-wide error storage. I guess that is what you currently do with the useJsonForms() invocation. If you have that use case more often you might want to extract this into an own custom binding, e.g. withErrorsForObjectProps or something like that.
Alternatively, as title and placeholder doesn’t seem to be rendered as inputs anyway and your’e probably just interested in the errors of the postalCode.value you could:

  • just determine the errors for postalCode.value and show them in your postalCode renderer. Again this can be done via a custom binding (especially if you have the object → value pattern more often).
  • or just use a control pointing to #/properties/postalCode/properties/value instead of #/properties/postalCode. Then the error determination of JSON Forms would work out of the box and your custom renderer just needs to look up the sibling values to render the title etc.

However in general this kind of JSON Schema and custom renderer usage is relatively uncommon. You usually don’t want to model meta data like title, tooltipText and placeholder as object properties in the JSON Schema and therefore include them in the data object. Are you developing some kind of form editor?

If not I would rather expect a JSON Schema like this:

postalCode: {
  type: 'string',
  format: 'postalCode',
  title: 'your-title',
  placeholder: 'your-placeholder',
  tooltipText: 'your-tooltipText'
} 

Wait so how would one receive data like title , tooltipText and placeholder in case one builds custom renderes.

Here is a screenshot of my tester.

You get the current (sub)schema handed over via props, so a simple approach (e.g. without i18n support) would just to take them from there, e.g.

export const TextField: FC<ControlProps> = ({
  data,
  schema,
  uischema,
  path,
  errors,
  enabled,
  visible,
  id
}) => (
visible && <TextInput
  id={id}
  title={schema.title}
  tooltipText={schema.tooltipText}
  placeholder={schema.placeholder}
  errorMessage={errors}
  disable={!enabled}
  value={data}
  onChange={ ev => handleChange(path, ev.target.value)}
/>
);