How to implement conditional required field validation

[Nanda]

Hi,
I am trying to implement condition based required validation. But its not working.
I have dropdown with values circle, square and rectangle.
If I select circle then “radius” property is required.
If I select square then “height” property is required.
If I select rectangle then “height” and “Width” properties are required.
But none of the validations are working. Am I miss anything?
Schema:

{
  "type": "object",
  "properties": {
    "shapeType": {
      "type": "string",
      "enum": [
        "",
        "square",
        "circle",
        "rectangle"
      ]
    },
    "shapeProperties": {
      "properties": {
        "radius": {
          "type": "number"
        },
        "height": {
          "type": "number"
        },
        "width": {
          "type": "number"
        }
      },
      "allOf":[
        {
          "if": {
            "properties": {
              "shapeType": {
                "const": "square"
              }
            },
            "required": [
              "shapeType",
              "shapeProperties"
            ]
          },
          "then": {
            "required": [
              "height"
            ]
          }
        },
        {
          "if": {
            "properties": {
              "shapeType": {
                "const": "circle"
              }
            },
            "required": [
              "shapeType",
              "shapeProperties"
            ]
          },
          "then": {
            "required": [
              "radius"
            ]
          }
        },
        {
          "if": {
            "properties": {
              "shapeType": {
                "const": "rectangle"
              }
            },
            "required": [
              "shapeType",
              "shapeProperties"
            ]
          },
          "then": {
            "required": [
              "height",
              "width"
            ]
          }
        }
      ]      
    }
  },
  "if": {
    "properties": {
      "shapeType": {
        "const": "square"
      }
    },
    "required": [
      "shapeType"
    ]
  },
  "then": {
    "required": [
      "shapeProperties"
    ]
  }
}

UI Schema

{
  "type": "VerticalLayout",
  "elements": [
    {
      "type": "Group",
      "label": "Shape Type",
      "elements": [
        {
          "type": "Control",
          "label": "Shape Type",
          "scope": "#/properties/shapeType"
        }
      ]
    },
    {
      "type": "Group",
      "label": "Shape Properties",
      "elements": [
        {
          "type": "Control",
          "label": "Radius",
          "example": "Ex: 5467234786",
          "scope": "#/properties/shapeProperties/properties/radius"
        },
        {
          "type": "Control",
          "label": "Height",
          "scope": "#/properties/shapeProperties/properties/height"
        },
        {
          "type": "Control",
          "label": "Width",
          "scope": "#/properties/shapeProperties/properties/width"
        }
      ],
      "rule": {
        "effect": "SHOW",
        "condition": {
          "scope": "#/properties/shapeType",
          "schema": {
            "enum": [
              "square",
              "circle",
              "rectangle"
            ]
          }
        }
      }
    }
  ]
}

Hi Nanda, you can easily test your schema validation by running AJV yourself or even trying an online tool.

Here your nested if schemas in the allOf will always evaluate to false because the if is scoped to shapeProperties but your refer to a shapeType which doesn’t exist for shapeProperties.

You can restructure your schema a bit to solve the issue:

{
  "type": "object",
  "properties": {
    "shapeType": {
      "type": "string",
      "enum": ["", "square", "circle", "rectangle"]
    },
    "shapeProperties": {
      "properties": {
        "radius": {
          "type": "number"
        },
        "height": {
          "type": "number"
        },
        "width": {
          "type": "number"
        }
      }
    }
  },
  "if": {
    "not": {
      "properties": {
        "shapeType": {
          "const": ""
        }
      }
    }
  },
  "then": {
    "required": ["shapeProperties"]
  },
  "allOf": [
    {
      "if": {
        "properties": {
          "shapeType": {
            "const": "square"
          }
        }
      },
      "then": {
        "properties": {
          "shapeProperties": {
            "required": ["height"]
          }
        }
      }
    },
    {
      "if": {
        "properties": {
          "shapeType": {
            "const": "circle"
          }
        }
      },
      "then": {
        "properties": {
          "shapeProperties": {
            "required": ["radius"]
          }
        }
      }
    },
    {
      "if": {
        "properties": {
          "shapeType": {
            "const": "rectangle"
          }
        }
      },
      "then": {
        "properties": {
          "shapeProperties": {
            "required": ["height", "width"]
          }
        }
      }
    }
  ]
}

This will work fine in JSON Forms as long as at least the empty shapeProperties object is given. You will see no errors when shapeProperties is undefined as AJV then reports an error which can’t be mapped to the UI by default.

To solve this you can either make sure that shapeProperties always exists (for example by preprocessing your data) or by adding or customizing some renderer for which you want to show this error.