How to add conditional required validation on nested object controls in jsonforms? - jsonschema

I am using version 2.5.1 with react material renderer, with custom renderers for string, number, radio, and date.
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"married": {
"type": "string",
"enum": [
"Married",
"Single"
]
},
"child": {
"type": "object",
"properties": {
"child_name": {
"type": "string"
},
"child_married": {
"type": "string",
"enum": [
"Married",
"Single"
]
},
"child_address": {
"type": "string"
},
"grandChild": {
"type": "object",
"properties": {
"grand_child_name": {
"type": "string"
},
"grand_child_married": {
"type": "string",
"enum": [
"Married",
"Single"
]
},
"grand_child_city": {
"type": "string"
},
}
}
}
}
}
}
Following are the rules we need to implement
/properties/name , /properties/married are always visible and required
If properties/married is = “Married”
then /properties/child/child_married, /properties/child/ child_name, /properties/child/
child_name are visible and required.
If properties/child/child_married = “Married”
then /properties/child/grandChild/grand_child_married,
/properties/child/grandChild/grand_child_name,
/properties/child/grandChild/grand_child_city Are visible and required.
I was able to show/hide the respective properties based on the enum values in uischema using rules.
The problem I am facing is how to conditionally add the required property to the schema at such a deeply nested level?

Related

Cannot find classification schema reference in JSON Schema

I have a product schema which tries to reference an id in my document. It is a common reference to multiple objects. Unfortunately, my ide claims classification reference cannot be found. I am very new to json schemas and find only snippets which don't quite show how the references are supposed to work. Here is my schema.
{
"$schema": "https://json-schema.org/draft-07/schema#",
"$id": "https://digital.com/schemas/products",
"description": "Schema for Product Data",
"title": "Products",
"type": "object",
"required": ["products"],
"properties": {
"products": {
"type": "array"
},
"options": {
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": {
"type": "string"
},
"productName": {
"type": "string"
},
"categories": {
"type": "object",
"additionalProperties": false,
"allOf": [
{ "$ref":"/products/classification" }
]
},
"productType": {
"type": "string",
"enum": ["electronic", "digital", "internet", "video"]
}
},
"required": ["productId"]
}
},
"classification": {
"$id": "/products/classification",
"type":"object",
"properties": {
"relevance-score": {
"type":"integer",
"minimum": 1,
"maximum": 5
},
"group":{
"enum":["adult","teen","seniors"]
}
}
},
"definitions": {
"mp4": {
"type": "object",
"properties": {
"mediaType": {
"type": "string",
"enum": ["video"]
},
"playlength": {
"type": "integer"
}
}
}
},
"mp3": {
"type": "object",
"properties": {
"mediaType": {
"enum": ["audio"]
}
}
}
}
}
I have defined a classification object to use in the class property of categories object like this
"$id":"/products/classification".
I tried setting it relative to the $id at the top of the document which is "https://digital.com/schemas/products" but I'm sure I haven't set it correctly. I want to use the classification object in the allOf property of the categories object.
Your reference is "$ref": "/products/classification". Where is this supposed to point?
Odds are the validator you're using is looking for a schema with the $id of "https://digital.com/products/classification". If the validator doesn't know about this schema (or perhaps is searching for that file), it can't get to it.
The other possibility is that you intend this to be a JSON Pointer. If that's the case, it needs to be URI-formatted: "#/products/classification"
However, this location doesn't existin within your schema, so it'll need to be updated.

JSON-schema exclude properties (opposite to required properties)

in JSON-schema, one can require certain keys in an object, see this example, taken from the json schema docs:
{
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string" },
"address": { "type": "string" },
"telephone": { "type": "string" }
},
"required": ["name", "email"]
}
I need the opposite: Is there a way to forbid or prevent a certain key from being in an object? Specifically, I want to prevent users from having an empty key inside an object:
{
"": "some string value"
}
You can exclude certain keys by name with:
{
"not": {
"anyOf": [
{ "required": [ "property1" ] },
{ "required": [ "property2" ] },
{ "required": [ "property3" ] },
...
]
}
https://json-schema.org/understanding-json-schema/reference/combining.html
Next to excluding keys with the not syntax (see answer by Ether), it is possible to achieve the goal with property-names.
In the following example, all keys have to map to a string URI. We furthermore exclude all keys that are not alphanumeric (via pattern), or don't have a specific length (via minLength). Other than that, we have no restrictions on keys.
"SomeKeyToBeValidated": {
"type": "object",
"properties": { },
"propertyNames": {
"type": "string",
"minLength": 1,
"pattern": "^[a-zA-Z0-9]*$"
},
"additionalProperties": {
"type": "string",
"format": "uri"
}
}

Json Schema dependency on outer field

Given a json structure like this
{
"name": "John Doe",
"billing_address": "123 main st",
"payment_details":{"credit_card": 55555555}
}
I need to make 'billing_address' a required field if payment_details.credit_card exists.
I've started from this example that achieves so if both fields were at the same level of nesting
{
"type": "object",
"properties": {
"name": { "type": "string" },
"credit_card": { "type": "number" }
},
"required": ["name"],
"dependencies": {
"credit_card": {
"properties": {
"billing_address": { "type": "string" }
},
"required": ["billing_address"]
}
}
}
However, what is the syntax to require this field that is one level above the dependant field?
That's too complicated for 'dependencies', so we go back to an if/then/else clause for that. We place these keywords at the top level, where the required field needs to be. In pseudocode: "if there is a payment_details property present, and it has a credit_card property, then require billing_address."
{
...,
"if": {
"type": "object",
"required": [ "payment_details" ],
"properties": {
"payment_details": {
"type": "object",
"required": [ "credit_card" ]
}
},
"then": {
"type": "object",
"required": [ "billing_address" ]
}
}
Note that the "type" and "required" keywords are required here -- as data of different types (for example an array) will cause object-specific keywords like "properties" and "required" to always evaluate to true.
thanks Ether! this worked, but only after adding the credit card as a property, in the if section.
the full if statement looks like this
"if": {
"type": "object",
"required": ["payment_details"],
"properties": {
"payment_details": {
"type": "object",
"properties": {
"credit_card": {}
},
"required": ["credit_card"]
}}},
the full json schema looks like this
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"billing_address": {
"type": "string"
},
"payment_details": {
"type": "object",
"properties": {
"credit_card": {
"type": "integer"
}
}
}
}
,
"if": {
"type": "object",
"required": ["payment_details"],
"properties": {
"payment_details": {
"type": "object",
"properties": {
"credit_card": {}
},
"required": ["credit_card"]
}}},
"then": {
"type": "object",
"required": [ "billing_address" ]
}
}

Angular6 JSON schema form for Array of Items

I am trying out Angular6 JSON form for my application and stuck in the issue of having array schema
The basic layout looks like
{
"schema": {
"type": "array",
"properties": {
"type": { "type": "string" },
"number": { "type": "string" },
}
},
"layout": [
{
"type": "array",
"items": [ {
"type": "div",
"displayFlex": true,
"flex-direction": "row",
"items": [
{ "key": "type", "flex": "1 1 50px",
"notitle": true, "placeholder": "Type"
},
{ "key": "number", "flex": "4 4 200px",
"notitle": true, "placeholder": "Phone Number"
}
]
} ]
}
],
"data": [
{ "type": "cell", "number": "702-123-4567" },
{ "type": "work", "number": "702-987-6543" }
]
}
But I am not getting the expected outcome, that is Form is prefilled with the data
[
{ "type": "cell", "number": "702-123-4567" },
{ "type": "work", "number": "702-987-6543" }
]
Refer: https://hamidihamza.com/Angular6-json-schema-form/
Based on your code there are some parts you may need to revisit.
The schema type should be either an object or boolean based on the documentation http://json-schema.org/latest/json-schema-core.html
Within the schema section, it seems that you want the type and number to be your properties of a JSON instance. Having this you can only pass one instance of data to the framework to fill in your properties because the framework cannot decide on which value to use for your property of type string.
In case of looking for having an array of type and number, you can have a property like "phone number" with the type array. below is an example from angular6-json-schema flex layout example which I think you had as your reference.
"schema": {
...
"phone_numbers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": { "type": "string", "enum": [ "cell", "home", "work" ] },
"number": { "type": "string" }
},
"required": [ "type", "number" ]
}
And pass your data having something as follows:
"data": {
...
"phone_numbers": [
{ "type": "cell", "number": "702-123-4567" },
{ "type": "work", "number": "702-987-6543" }
],
}

Using a json schema in multiple layouts

I'm helping to build an interface that works with Json Schema, and I have a question about interface generation based on that schema. There are two display types - one for internal users and one for external users. Both are dealing with the same data, but the external users should see a smaller subset of fields than the internal users.
For example, here is one schema, it defines an obituary:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "",
"type": "object",
"required": [
"id",
"deceased"
],
"properties": {
"id": { "type": "string" },
"account": {
"type": "object",
"required": [
"name"
],
"properties": {
"id": { "type": "number" },
"name": { "type": "string" },
"website": {
"anyOf": [
{
"type": "string",
"format": "uri"
},
{
"type": "string",
"maxLength": 0
}
]
},
"email": {
"anyOf": [
{
"type": "string",
"format": "email"
},
{
"type": "string",
"maxLength": 0
}
]
},
"address": {
"type": "object",
"properties": {
"address1": { "type": "string" },
"address2": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" },
"postalCode": { "type": "string" },
"country": { "type": "string" }
}
},
"phoneNumber": {
"anyOf": [
{
"type": "string",
"format": "phone"
},
{
"type": "string",
"maxLength": 0
}
]
},
"faxNumber": {
"anyOf": [
{
"type": "string",
"format": "phone"
},
{
"type": "string",
"maxLength": 0
}
]
},
"type": { "type": "string" }
}
},
"deceased": {
"type": "object",
"required": [
"fullName"
],
"properties": {
"fullName": { "type": "string" },
"prefix": { "type": "string" },
"firstName": { "type": "string" },
"middleName": { "type": "string" },
"nickName": { "type": "string" },
"lastName1": { "type": "string" },
"lastName2": { "type": "string" },
"maidenName": { "type": "string" },
"suffix": { "type": "string" }
}
},
"description": { "type": "string" },
"photos": {
"type": "array",
"items": { "type": "string" }
}
}
}
Internal users would be able to access all the fields, but external users shouldn't be able to read/write the account fields.
Should I make a second schema for the external users, or is there a way to indicate different display levels or public/private on each field?
You cannot restrict acess to the fields defined in a schema, but you can have 2 schema files, one defining the "public" fields, and the other one defining the restricted fields plus including the restricted fields.
So
public-schema.json:
{
"properties" : {
"id" : ...
}
}
restricted-schema.json:
{
"allOf" : [
{
"$ref" : "./public-schema.json"
},
{
"properties" : {
"account": ...
}
}
]
}