Unclear of how to implement ajv-errors to display customer error messages below the label/input element

Hi all,

Thank you for your help in advance.
I do not seem to get of how to implement ajv-errors into JSON Forms to display custom error messages on the DOM, basically to replace the default “is required property” message.
I have followed the instructions, but it does not overwrite the message, i was able to get custom message printed inside console, but how do i pass it to JSON Forms to overwrite the default?
I am sure it is something simple.

I am using:

"ajv": "^8.6.3",
"ajv-errors": "^3.0.0",    
"@jsonforms/core": "^3.0.0-alpha.2",
"@jsonforms/examples": "^3.0.0-alpha.2",
"@jsonforms/material-renderers": "^3.0.0-alpha.2",
"@jsonforms/react": "^3.0.0-alpha.2",
"@jsonforms/vanilla-renderers": "^3.0.0-alpha.2"

Code below:

const schema = {
  type: 'object',
  errorMessages: {
    type: 'should be an object',
    required: {
      description: 'description field is missing',
    },
  },
  properties: {
    description: {
      title: 'Long Description',
      type: 'string',
      minLength: 3,
      errorMessage: {
        required: 'foo must be an Integer',
      },
    },
  },
  required: ['description'],
  additionalProperties: false,
};

const initialData = {
  description: undefined,
};

const Ajv = require('ajv').default;
const ajv = new Ajv({
  allErrors: true,
  messages: true,
  strict: false,
  timestamp: true,
  ownProperties: true,
  verbose: true,
});

const validate = ajv.compile(schema);
console.log(validate(initialData));
console.log(validate.errors);

const App = () => {
  const [jsonformsData, setJsonformsData] = useState(initialData);

  return (
    <div className='App App-header'>
      <JsonForms
        ajv={ajv}
        schema={schema}
        uischema={uischema}
        data={jsonformsData}
        renderers={materialRenderers}
        cells={materialCells}
        onChange={({ errors, data }) => {
          setJsonformsData(data);
        }}
      />
    </div>
  );
};

image

Best regards,
KK

Hi @karolis-k,

I don’t really see ajv-errors being used in the provided code. You need to wrap your AJV instance with ajv-errors and then hand over this instance to JSON Forms.

Unrelated note: Ideally you should use the createAjv method exported by @jsonforms/core to make sure you always have the options set which JSON Forms requires (except when you override them again).


Note that with the latest prerelease we now have i18n support in JSON Forms which also allows to customize the error messages. There is no documentation yet but it should be rather straightforward. If you want to use it: You can hand over an i18n object to the root component containing a translate function which is of type

(key: string, defaultMessage: string | undefined, args: any) => string | undefined

This translate function should return the defaultMessage when you don’t have a translation for the given key.

hi, What do you mean

hand over an i18n object to the root component

do you have a more small sample of this?
also, could you update the documentation, to be a bit more intuitive. it is a core functionality after all.

many thanks
V

Hi @valtido,

there are no surprises here. Handing over an i18n object means to set the i18n prop. It is an object and can contain a translate function of the type mentioned above.

If you need some guidance you can check out the Vue Vanilla example app in the JSON Forms repository or the Vue2 Vuetify example app. Alternatively you could look at the test cases.

This internationalization support is very new and still not released in a stable version. Of course we intend to document it. The JSON Forms documention is open source too, so feel free to contribute :wink:

Using a snipped from the Original Question, how can I override the error messages?
I am happy to help with documentation of it afterwards.

I am not sure how I can override these messages from “is a required property” to “custom text message here”

I think, I may have confused you on my question above.

In case you are using ajv-errors like in the original question then using errorMessage.required within JSON Schema should be fine. Create a new AJV instance outside of JSON Forms using our exported createAjv function and apply ajv-errors to it. Then hand over the instance via the ajv prop to JSON Forms. Note that we switched from AJV v6 to v8 in one of the 3.0.0 pre releases, so depending on the version of JSON Forms you’re using you need the respective ajv-errors version.

When you want to use our internationalization support for overwriting error messages then you can just check with which keys and default messages the translation function is called and then return your own text.

For required it should be called with the key starting with must have required property {propertyname} (as this is the original AJV error message), <datapath>.error.required (e.g. name.error.required) and error.required. Return your custom message for any of them and it will be used.

I would recommend using the following translation function:

const translator = (key, defaultMessage) => {
  console.log(`Key: ${key}, Default Message: ${defaultMessage}`);
  return defaultMessage;
};

<JsonForms
  i18n={{translate: translator}} />

This way you can easily see what keys are used in JSON Forms for your forms.

Hi, Stefan,

I’ve tried to do as advised, on a typescript app and I’m getting an error.

const translator = (id: string, defaultMessage: string) => {
        console.log(`Key: ${id}, Default Message: ${defaultMessage}`);
        return defaultMessage;
    };
<JsonForms
                i18n={{translate: translator}}
                schema={schema}
                uischema={uischema}
                data={data}
                renderers={materialRenderers}
                cells={materialCells}
                onChange={({ data, errors }) => setData(data)}
            />
Type '(id: string, defaultMessage: string) => string' is not assignable to type 'Translator'.
  Types of parameters 'defaultMessage' and 'defaultMessage' are incompatible.
    Type 'undefined' is not assignable to type 'string'.  TS2322

I noticed that the type if the Translator is

export declare type Translator = {
    (id: string, defaultMessage: string, values?: any): string;
    (id: string, defaultMessage: undefined, values?: any): string | undefined;
};

Can you please advise? Thanks!

Hi @acis,

the defaultMessage could also be undefined. Your translator type needs to be adjusted for that, e.g.

const translator = (id: string, defaultMessage: string | undefined) => {
        console.log(`Key: ${id}, Default Message: ${defaultMessage}`);
        return defaultMessage;
    };

Returning defaultMessage here leads to JsonForms complaining about the type returned. I solve it by returning defaultMessage as string, but I am not sure this is the right approch.

Hi @Icenwharth,

Seems we should improve our Translator type a bit. We only specified an overloaded defaultMessage: string and defaultMessage: undefined. My guess is that we should also offer a defaultMessage: string | undefined to express that returning string | undefined is fine there.

For now I would suggest just casting your translate function to the type Translator. Note that I would not recommend using the name translateErrors as we also offer a translateError. This might lead to confusion. I would just name it translate.

I solve it by returning defaultMessage as string, but I am not sure this is the right approch.

Also works. Just make sure to only type cast and not really always returning a string.