Using rule SHOW against an array of objects with multiple target values

I’m having trouble with getting a SHOW rule to work when using it against an array of objects, where there is a list of values that should trigger the form elements to be shown.

I’m using react JSONForms, v3.1.0 with react v18.2.0.

It’s always showing the form elements, no matter what the array values are, even if the array is empty. I’ve tried many different variations with the rule’s condition, but I have no idea if I’m even getting close to a correct answer since I’m not successfully finding examples that are using arrays of objects.

This is a simplified schema. The issue I’m having troubles with, on the rule SHOW starts on line 40 with the HorizontalLayout control. This element should be shown if an animals array item has an ontology_id value of : “cats”, “kittens”, or “felines”.

{
    "properties": {
        "animals": {
            "items": {
                "properties": {
                    "ontology_id": { "type": "string" },
                    "ontology_label": { "type": "string" },
                    "text": { "type": "string" }
                },
                "type": "object"
            },
            "type": "array"
        },
        "cats": {
            "type": "object",
            "properties": {
                "name": { "type": "string" },
                "warrior": { "type": "boolean" },
                "clan": { "type": "string" },
                "kittypet": { "type": "boolean" },
                "twoleg_friend": { "type": "string" }
            }
        }
    }
}

And the schema UI:

{
    "type": "VerticalLayout",
    "elements": [
        {
            "type": "Control",
            "label": "Animals",
            "scope": "#/properties/animals/",
            "options": {
                "elementLabelProp": "text",
                "detail": {
                    "type": "HorizontalLayout",
                    "elements": [
                        {
                            "type": "Control",
                            "label": "Animal",
                            "scope": "#/properties/text"
                        },
                        {
                            "type": "autocomplete",
                            "label": "Animal ontology label",
                            "scope": "#/properties/ontology_label",
                            "options": {
                                "optionName": "name",
                                "listurl": "/edit/list/animals.json",
                                "updateOtherFields": [
                                  { "optionName": "name", "field": "text" },
                                  { "optionName": "id", "field": "ontology_id" }
                                ]
                            }
                        },
                        {
                            "type": "Control",
                            "label": "Animal ontology ID",
                            "scope": "#/properties/ontology_id"
                        }
                    ]
                }
            }
        },
        {
            "type": "HorizontalLayout",
            "rule": {
                "effect": "SHOW",
                "condition": {
                    "scope": "#/properties/animals/items/properties/ontology_id",
                    "type": "LEAF",
                    "expectedValue": [
                        "cats",
                        "kittens",
                        "felines"
                    ]
                }
            },
            "elements": [
                {
                    "type": "Fieldset",
                    "label": "Warrior cat",
                    "elements": [
                        {
                            "type": "Control", "label": "Cat name",
                            "scope": "#/properties/cats/properties/name"
                        }, {
                            "type": "Control", "label": "Warrior?",
                            "scope": "#/properties/cats/properties/warrior"
                        }, {
                            "type": "Control", "label": "Clan",
                            "scope": "#/properties/cats/properties/clan"
                        }, {
                            "type": "Control", "label": "Was a kittypet?",
                            "scope": "#/properties/cats/properties/kittypet"
                        }, {
                            "type": "Control", "label": "twoleg owner",
                            "scope": "#/properties/cats/properties/twoleg"
                        }
                    ]
                }
            ]
        }
    ]
}

I should note that the autocomplete control is based upon MUI material’s autocomplete, but is able to update multiple fields from the url’s selected object. The Fieldset control just wraps its children in a fieldset html element, with an optional label.

Is there anything else you would need to see? I’m not sure how to setup a working example to show how this is/isn’t working. Is there a doc that shows how to setup a react jsonforms example?

Thanks greatly for your time and help!

I figured out how to setup a sandbox to illustrate this example.

Here is the basic example using the above schema and schema UI.

codesandbox.io - react JSONForms using Rule SHOW using an array of objects

I think I also figured out that "type": "LEAF" is not part of the current condition so I removed it in this example.

Hi @rbluer,

There are multiple problems here:

  • The first one is that expectedValue is doing a simple === for value comparison while you want it to behave like a “OR”. Using the old school conditions you would need to set up a lot of “OR” conditions.
    I would rather suggest using schema based rules as described in the documentation. This would then look like this:
    "condition": {
      "scope": "", // let's skip the scope for now, see second point
      "schema": {
        "enum": ["cats", "kittens", "felines"]
      }
    }
    
  • The second issue is that the scope is not valid (which is why I left it empty above). In JSON Forms you can not generically refer to “any array item” with a scope. The scope is used for two purposes: Resolving a path to a sub-schema of the JSON Schema and determining a path in the actual data object. While the first purpose will work fine here, the second purpose will not as we can’t just generically resolve to arbitrary array items.

However the schema based rules are very powerful so you can just adapt the scope and schema a bit to express what you want to see:

"condition": {
  "scope": "#",
  "schema": {
    "properties": {
      "animals": {
        "type": "array",
        "contains": {
          "properties": {
            "ontology_id": {
              "enum": ["cats", "kittens", "felines"]
            },
            "required": ["ontology_id"]
          }
        }
      }
    },
    "required": ["animals"]
  }
}

This schema based rule will apply if the animals array exists and contains at least one entry whose ontology_id is either "cats", "kittens", or "felines".

Oh wow! Thanks for that information and explanations. That really does put it all in to the proper context and makes a ton of sense now.

So, in a rough way, I was kind of close with one of my attempts with the use of the schema, but at the same time, I was way off because I was incorrectly using the array references and did not have the two needed ‘required’ attributes. No, I would not have been able to figure it out since there were too many moving parts and I did not understand them too well to begin with.

Thanks again for your detailed explanations. It not only helps me get past my current challenge, but has given me a far better understanding of how to use these in the future on other more complex requirements.

For the sake of anyone who has similar needs with figuring out how to use the rule on an array of objects, here is the final “rule”, which correctly places the inner ‘required’ (trivial to correct) as a sibling to the array.

"rule": {
  "effect": "SHOW",
  "condition": {
    "scope": "#",
    "schema": {
       "properties": {
        "animals": {
          "type": "array",
          "contains": {
            "properties": {
              "ontology_id": {
                "enum": ["cats", "kittens", "felines"]
              }
            },
            "required": ["ontology_id"]
          }
        }
      },
      "required": ["animals"]
    }
  }
}

And this is an updated functional example that now works perfectly…
Funcitonal example of rule SHOW against an array of ojects with multiple target values

-Blue

1 Like