Rule: scope refer to property outside the current group

Hi everyone, I have a uiSchema like below:

{
  "type": "VerticalLayout",
  "elements": [
    {
      "type": "VerticalLayout",
      "scope": "#/properties/example",
      "elements": [
        {
          "type": "Control",
          "scope": "#/properties/studentID"
        },
        {
          "type": "Control",
          "scope": "#/properties/43438835133134845",
          "mode": "typing",
          "rule": {
            "effect": "SHOW",
            "condition": {
              "scope": "#/properties/studentID",
              "schema": {
                "const": "1"
              }
            }
          }
        }
      ]
    },
    {
      "type": "Control",
      "scope": "#/properties/name"
    },
    {
      "type": "Control",
      "scope": "#/properties/age"
    }
  ]
}

I want the value of the “scope” property in “condition” to refer to the property outside the group it belongs to? As above: besides just referring to inside group property(just only studentID), I also want to refer to outside(name/age) properties
Is it possible? If possible, how?

Hi @autinn123,

The scope of a condition can point to arbitrary data. So for example in your rule you could use a scope of #/properties/name, #/properties/age or even the root object (#) without a problem.

1 Like

Yeah, I’ve just tried and I get it now. Thank you @sdirix

1 Like
const schema= {
	"order": 0,
	"type": "object",
	"properties": {
		"age": {
			"type": "string",
			"title": "age",
			"order": 1
		},
		"insureds": {
			"order": 0,
			"type": "array",
			"items": {
				"properties": {
					"selectedPlanId": {
						"type": "string",
						"title": "selectedPlanId",
						"order": 0
					}
				},
				"type": "object"
			},
			"title": "insureds"
		},
		"name": {
			"type": "object",
			"title": "name",
			"order": 1,
			"properties": {
				"firstName": {
					"type": "string",
					"title": "first name",
					"order": 0
				},
				"last name": {
					"type": "string",
					"title": "last name",
					"order": 1
				}
			},
			"required": [
				"firstName",
				"last name"
			]
		}
	},
}

const uiSchema = {
	"type": "VerticalLayout",
	"elements": [
		{
			"type": "Control",
			"scope": "#/properties/age",
			"mode": "typing"
		},
		{
			"type": "VerticalLayout",
			"scope": "#/properties/insureds",
			"elements": [
				{
					"type": "Control",
					"scope": "#/properties/selectedPlanId"
				}
			]
		},
		{
			"type": "Group",
			"elements": [
				{
					"type": "Control",
					"scope": "#/properties/name/properties/firstName",
					"mode": "typing"
				},
				{
					"type": "Control",
					"scope": "#/properties/name/properties/last name",
					"mode": "typing",
					"rule": {
						"effect": "SHOW",
						"condition": {
							"scope": "#/properties/insureds/items/properties/selectedPlanId",
							"schema": { "const": "aaa" },
						}
					}
				}
			],
			"validation": []
		}
	]
}

In this case conditon does not work when I point the key (selectedPlanId) in an array @sdirix . Please help

Hi @autinn123,

Can you elaborate on what exactly you’re trying to achieve?

Shall the last name property be shown when at least one selectedPlanId is aaa? If that is the case you need to point the condition scope to the array property itself and use a condition schema which reflects exactly that.

const schema = {

    order: 0,

    type: "object",

    properties: {

        age: {

            type: "string",

            title: "age",

            order: 1,

        },

        insureds: {

            order: 0,

            type: "array",

            items: {

                properties: {

                    selectedPlanId: {

                        type: "string",

                        title: "selectedPlanId",

                        order: 0,

                    },

                },

                type: "object",

            },

            title: "insureds",

        },

        name: {

            type: "object",

            title: "name",

            order: 1,

            properties: {

                firstName: {

                    type: "string",

                    title: "first name",

                    order: 0,

                },

                "last name": {

                    type: "string",

                    title: "last name",

                    order: 1,

                },

            },

            required: ["firstName", "last name"],

        },

    },

}

const uiSchema = {

    type: "VerticalLayout",

    elements: [

        {

            type: "Control",

            scope: "#/properties/age",

            mode: "typing",

        },

        {

            type: "VerticalLayout",

            scope: "#/properties/insureds",

            elements: [

                {

                    type: "Control",

                    scope: "#/properties/selectedPlanId",

                },

            ],

        },

        {

            type: "Group",

            elements: [

                {

                    type: "Control",

                    scope: "#/properties/name/properties/firstName",

                    mode: "typing",

                },

                {

                    type: "Control",

                    scope: "#/properties/name/properties/last name",

                    mode: "typing",

                    rule: {

                        effect: "SHOW",

                        condition: {

                            scope: "#/properties/insureds",

                            schema: {

                                type: "array",

                                items: {

                                    properties: {

                                        selectedPlanId: {

                                            const: "aaa",

                                        },

                                    },

                                },

                            },

                        },

                    },

                },

            ],

            validation: [],

        },

    ],

}

I fixed at you said, yes it worked, but condition just worked till I input at selectedPlanId something(when value = aaa then it show), the problem was at first I added first array’s item, last name had been shown although I set rule for it, it just was hidden when I input something(except = aaa) cc: @sdirix

and another question, just for another case. In case I want to set a rule for selectPlanId, I want selectPlanId just shows when value of age equal 18, how can I set a rule for it when it is in array, and it’s scope point to age which is in the outside of the array. I tried set it’s scope: #/property/age but it was not work

Hello, @sdirix! Could you, please, help me in this case: if I have detailed items, how can I get some data, that is outside of array?

{
    "scheme": {
        "type": "object",
        "properties": {
            "comments": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "date": {
                            "type": "string",
                            "format": "date"
                        },
                        "message": {
                            "type": "string",
                            "maxLength": 5
                        }
                    }
                }
            },
            "date": {
                "type": "string"
            }
        }
    },
    "ui": {
        "type": "VerticalLayout",
        "elements": [
            {
                "type": "Control",
                "scope": "#/properties/comments",
                "options": {
                    "detail": {
                        "type": "VerticalLayout",
                        "elements": [
                            {
                                "type": "Control",
                                "label": "Relative Path - OK",
                                "scope": "#/properties/message"
                            },
                            {
                                "type": "Control",
                                "label": "Relative Path - OK",
                                "scope": "#/properties/date"
                            },
                            {
                                "type": "Control",
                                "label": "Absolute Path - NOT OK",
                                "scope": "#../date"
                            }
                        ]
                    }
                }
            }
        ]
    }
}

Hi @dbautova and @autinn123 ,

This use case is currently not supported. Details are scoped to the respective part of the JSON Schema and can’t escape them.

The control use case can be solved by using a custom renderer: The custom renderer could apply itself for relative paths like ../date. Then it resolves the data, path, schema outside of it’s object/array, creates a new uischema control with an adjusted scope and then dispatches back to JSON Forms.

Note that this breaks some assumptions of the provided renderers like the array renderers. For example validation errors regarding this control will not show up in the array validation summary.

Overall I would recommend checking whether such a use case is really necessary. Seems weird that all array entries will have a synchronized date field which point to the very same attribute. It’s certainly not what I would expect within a UI.

The use case of an array control being shown/hidden based on an outside attribute makes more sense. Sadly that’s not possible at the moment but must also be handled via a custom renderer.

1 Like