Custom Validation

Our application has a number of different forms, with a variety of validation needs. I’ve done a bunch of reading up on JSON schema validation and I think I have an approach that will work for us. But, I wanted to run a particularly complex example by you guys to make sure I’m on the right path.

Requirements:

  1. An Array called addresses which allows a user to enter up to three types of addresses, Home, Alternate, and Work, where work is optional. I have this working fine with some custom renderers.
  2. Any field that is required should show on the form with a red label and the input should be outlined in red. Once that field is valid, the field outline should change from red to black, but the label stays red. I have this working as well.

The problem arises when I add custom validation rules to my schema. For example, Email should only be required on the objects which have a “type” value of either “Home” or “Alternate.” I used to have email in the required array at the top of the schema, but moved it to the conditional required statement at the bottom of the schema (see below). Now the email field on the Home and Alternate forms doesn’t have the required styling, although ajv correctly validates the form if no email is included on either of those objects.

So, to make sure the Email field has the correct styling, I was thinking about adding an “options”: { “required”: true } to the uischema for any element that has conditional validation logic. Then I could just handle it in my custom components as needed. Would that be a valid approach or is there a better way to handle this?

"addresses": {
  "type": "array",
  "items": {
    "type": "object",
    "itemLabel": "Address",
    "required": [
      "type",
      "address1",
      "city",
      "state",
      "zip"
    ],
    "properties": {
      "preferred": {
        "type": "boolean"
      },
      "type": {
        "type": "string",
        "enum": [
          "Work",
          "Home",
          "Alternate"
        ]
      },
      "address1": {
        "type": "string"
      },
      "address2": {
        "type": "string"
      },
      "city": {
        "type": "string"
      },
      "state": {
        "type": "string"
      },
      "zip": {
        "type": "string"
      },
      "country": {
        "type": "string"
      },
      "email": {
        "type": "string"
      }
    },
    "if": {
      "properties": {
        "type": {
          "const": "Home"
        }
      }
    },
    "then": {
      "required": ["email"],
      "errorMessage": {
        "required": {
          "email": "Email should be the correct format (eg email@emailprovider.com)."
        }
      }
    },
    "errorMessage": {
      "required": {
        "address1": "Address 1 is required.",
        "city": "City is required.",
        "state": "State is required.",
        "zip": "Zip is required."
      }
    }
  }
}

Hi @RTyska,

You are correct, JSON Forms is currently unable to compute the required prop in case it is dynamic. The required validation will still work. The underlying issue is that the required is hard to compute in dynamic scenarios, and may not even be decidable in case that the validation does not fail.

Of course many use cases are simpler than the worst cases, so for many of them it should generally be possible to calculate a dynamic required prop. In your case, with a simple if-condition that would be rather straightforward.

Using custom renderers, this is rather easy to add. You could code this in explicitly, as you mentioned in your suggestion with "options": { "required": true } or do it programmatically by analyzing the JSON Schema. You could even generalize this into another hook.

Personally I like approaches where it’s not required to add mandatory options to the UI Schema, as this is another point of potential desync between schema and UI Schema, so I would explore whether you can do without. However the UI Schema approach is definitely also fine and might make the code simpler, which is also a benefit. You might even consider placing more logic in the UI Schema then, similar to the already existing rules, so you don’t need to analyze the JSON Schema at all anymore.