AJV only validate on input

Hey,

As soon as my JSON forms loads up and the renderers get rendered, all of the fields get validated by AJV and they all turn red with the error messages. Is there a way to not trigger the validation on page load?

EDIT:
I found this in the coreReducer code:

case INIT: {
      const thisAjv = getOrCreateAjv(state, action);

      const validationMode = getValidationMode(state, action);
      const v = validationMode === 'NoValidation' ? undefined : thisAjv.compile(action.schema);
      const e = validate(v, action.data);

From the last line, it seems it will always validate the form when JSON Forms boots up. Is there any workaround to this?

Hi @adamsilva01,

You might want to try our validation modes. You can find the documentation for them here.

Hey @sdirix ,

But none of those modes validates only on input.
ValidateAndShow validates as soons as the form loads and shows all the errors
ValidateAndHide does the same except it will always hide the errors even after input
NoValidation doesn’t even validate.

Should I use ValidateAndHide when the form loads, and then change it to ValidateAndShow?

EDIT: This doesn’t work, as soon as the value changes to ValidateAndShow, the errors get shown again.

Basically I only want each input to validate itself when it’s changed and show an error if invalid, I don’t want the full page to show errors as soon as the form loads.

I guess what you’re asking for is showing errors subsequently this might has to do with ajv.

i dont recollect much but i had this issue where the errors where coming subsequently and i had to edit the property of ajv

ajv = createAjv({
allErrors: false
})

you can try setting allError to false with all other Error properties you have.

hope this helps.

Hi @adamsilva01,

We currently don’t offer “validate on input” out of the box. To achieve something like this you will need to write custom renderers (which can mostly just wrap our existing renderers), which track an additional “touched” state and only show their errors when touched

This is not really a useful solution. Yes only a subset of errors will be shown, but AJV can’t know which fields were touched and which weren’t and therefore the shown error will very likely not match the user input flow.

1 Like

Thanks for mentioning ive got a question how can you make an input entere element as invalid with jsonform.updateerrors

for example we can make it as min or max is there anyway we can make it as invalid like incase of api? also can show an example for jsonform.updateErrors for min or max in angular

Hi @howdyAnkit,

I would like to suggest to use the additionalErrors prop instead of dispatching an updateErrors action. You can find the documentation here.

Hey @sdirix ,

Nice! I managed to implement it quite easily since most of my renderers are already custom.
I’m just having an issue with my ObjectRenderer. In this case, it only displays/computes the errors when something is inserted. Meaning, before any letter is inserted in one of the fields, none of the fields get evaluated for errors (only the parent property does).

Not sure if there is anything I need to change in my ObjectRenderer? Now I’d rather this show all the errors even for ObjectRenderers, since I can now control them via the new touched property I created.

Here is my Object Renderer:

<template>
    <div v-if="control.visible">
        <dispatch-renderer :visible="control.visible"
                           :enabled="control.enabled"
                           :schema="control.schema"
                           :uischema="detailUiSchema"
                           :path="control.path"
                           :renderers="control.renderers"
                           :cells="control.cells" />
    </div>
</template>

<script lang="ts">
import {
    ControlElement,
    findUISchema,
    Generate,
    isObjectControl,
    JsonFormsRendererRegistryEntry,
    rankWith,
    UISchemaElement,
} from '@jsonforms/core'
import { DispatchRenderer, rendererProps, RendererProps, useJsonFormsControlWithDetail } from '@jsonforms/vue'
import { defineComponent } from 'vue'
import { useVanillaControl } from '@jsonforms/vue-vanilla'

const applyFormRenderObject = defineComponent({
    name: 'object-renderer',
    components: { DispatchRenderer },
    props: {
        ...rendererProps<ControlElement>(),
    },
    setup (props: RendererProps<ControlElement>) {
        const control = useVanillaControl(useJsonFormsControlWithDetail(props))
        return {
            ...control,
            input: control,
        }
    },
    computed: {
        detailUiSchema (): UISchemaElement {
            const uiSchemaGenerator = () => {
                return Generate.uiSchema(this.control.schema, 'VerticalLayout')
            }

            return findUISchema(
                this.control.uischemas,
                this.control.schema,
                this.control.uischema.scope,
                this.control.path,
                uiSchemaGenerator,
                this.control.uischema,
                this.control.rootSchema,
            )
        },
    },
})

export default applyFormRenderObject

export const entry: JsonFormsRendererRegistryEntry = {
    renderer: applyFormRenderObject,
    tester: rankWith(2, isObjectControl),
}
</script>

Hi @adamsilva01,

Does the object actually exist before any field is touched? AJV will not produce errors for properties for an object which is undefined. Once you edit a field JSON Forms will by default create the parent object if it does not exist which then let’s AJV report errors for all its properties.

To fix that you need to make sure that the object already exists in your data, either by initializing manually or using AJV’s default option.

Hey @sdirix ,

The data object is empty at the beginning. I tried using the both true and 'empty' for the useDefaults options, but none of those worked. I even tried creating the empty object on the data, but still didn’t work.

Here is the schema for the object being rendered using the ObjectRenderer I sent above:

"/personal/name": {
      "title": "Name",
      "description": "First and last name",
      "type": "object",
      "properties": {
        "first": {
          "type": "string",
          "minLength": 2,
          "maxLength": 30
        },
        "last": {
          "type": "string",
          "minLength": 2,
          "maxLength": 30
        }
      },
      "required": [
        "first",
        "last"
      ]
    },