JsonFormsDispatch visible prop is not respected

Hi,
I’m trying to implement custom handling of rules for fields inside arrays of objects.

schema:

{
   "type":"object",
   "properties":{
      "textInput":{
         "type":"string"
      },
      "itemsArray":{
         "type":"array",
         "items":{
            "type":"object",
            "properties":{
               "fieldToHide":{
                  "type":"string"
               }
            }
         }
      }
   }
}

uischema:

{
   "type":"VerticalLayout",
   "elements":[
      {
         "type":"Control",
         "scope":"#/properties/textInput",
         "label":"Text Input"
      },
      {
         "type":"Array",
         "scope":"#/properties/itemsArray",
         "options":{
            "detail":{
               "type":"VerticalLayout",
               "elements":[
                  {
                     "type":"Control",
                     "scope":"#/properties/fieldToHide",
                     "label":"Field to Hide"
                  }
               ],
               "rule":{
                  "effect":"HIDE",
                  "condition":{
                     "scope":"#/properties/textInput",
                     "schema":{
                        "const":"123"
                     }
                  }
               }
            }
         }
      }
   ]
}

In the array renderer, I’d like to resolve the rule for each field and pass the result to the visible prop of JsonFormsDispatch. The issue is that even if I hardcode visible={false}, at some point this value gets overridden and reset to true.

Does anyone know how to approach this so that visible doesn’t get overwritten? My goal is to use this to dynamically hide/show fields within object arrays.

Hi @nightingbear,

The visible is passed through, except for when there is a rule. Then the rule takes precedence.

I don’t understand however why you need to pass visible={false}. In this case you could also just not dispatch and skip rendering for this element. When given visible={false} our off-the-shelf renderers also just render nothing.

Hi, thanks for the reply,
Since rules applied to fields in an array of objects are not supported in JsonForms, I’d like to write a custom solution to handle this. For hide/show, I wanted to create a function that determines the visibility of each element so I could pass it to JsonFormsDispatch. That’s where I ran into a problem, because the value passed through the visible prop wasn’t reflected deeper in JsonFormsDispatch and didn’t affect the display of the elements.

The only time we ignore a handed over visible property is if there is an actual rule attached to the UI Schema element. The result of the rule evaluation takes higher precedence than a handed over visible prop.

I don’t understand. Did you hand over a function instead of a boolean to the visible prop of the Dispatcher? If yes, then the function will always be interpreted as a truthy, i.e. it’s the same as handing over visible: true.

I wasn’t clear - what I meant is that I’m passing to the visible prop whatever is returned by the custom function that resolves visibility for fields in the array of objects. But what I’m passing doesn’t actually affect whether JsonFormsDispatch is visible or not.

For HIDE, I worked around it by conditionally rendering JsonFormsDispatch, but it becomes a real problem with SHOW. I have a SHOW rule for a field in an array of objects - at the start, the field is correctly hidden, but when the rule’s conditions are met, it doesn’t appear, even though visible in JsonFormsDispatch changes to true.

That’s why it seems like what I’m passing to the visible prop in JsonFormsDispatch doesn’t matter and is being overridden somewhere else.

Maybe it’s happening because, as you mentioned, visible is being ignored since the field has a rule - but the rule for a field inside an array of objects isn’t natively handled correctly, so visible doesn’t update even when the conditions for SHOW are met.

Is that a possible scenario?

Hi @nightingbear,

It’s hard to determine what is going wrong without seeing the code. As I said before, only rules take precedence, so if the visible is changed under you, then because a rule was evaluated. You can also debug to check what is overwriting your visible.

I still don’t understand why the code on your side does not look like this:

// somewhere in JSX
{ visible ? <JsonFormsDispatch /> : null }

This dispatches when you calculated visible to true and hides when visible is false. There is no need to pass visible to the Dispatch. The only thing you need to make sure of is that the parent component is rerendered whenever your calculated visible needs to change value.

Hi @sdirix, when I said “I conditionally render JsonFormsDispatch” I meant exactly what you described. Agree - it’s hard to talk about code without code :slight_smile: So I prepared a CodeSandbox with the issue I’ve been describing - https://codesandbox.io/p/sandbox/35k4sn

MaterialArrayLayoutRenderer was copied from your repo; I only modified it in the ExpandPanelRendererComponent , line 239, where I added conditional rendering based on the result of the isElementVisible function for a given element.

In App , there’s a schema and uischema with rules applied - allOf in the schema and a rule in the uischema. The SHOW rule (which I’m having trouble with) is uncommented, and the HIDE rule (which works correctly) is commented out. Even though the condition for SHOW is met and isElementVisible returns true (as seen in the console log), the element still doesn’t show.

I hope what I explained earlier makes more sense now.

The result of isElementVisible is completely unrelated to the issue. Even if you always return true or remove the call altogether, the control will not render. In fact all of the customization which is implemented in the CodeSandbox has no effect.

The control does not render because you defined a UI Schema rule for it. This rule is in a “detail” of the array UI Schema element:

{
    type: "VerticalLayout",
    elements: [
      {
        type: "HorizontalLayout",
        elements: [
          {
            type: "Control",
            scope: "#/properties/someField",
            label: "Some field",
          },
        ],
      },
      {
        type: "HorizontalLayout",
        elements: [
          {
            type: "Control",
            scope: "#/properties/someObject",
            options: {
              itemsType: "object",
              detail: {
                type: "HorizontalLayout",
                elements: [
                  {
                    type: "Control",
                    scope: "#/properties/someObjectField",
                    label: "Some object field",
                    rule: {
                      effect: "SHOW",
                      condition: {
                        type: "SCHEMA",
                        scope: "#",
                        schema: {
                          anyOf: [
                            {
                              allOf: [
                                {
                                  properties: {
                                    someField: {
                                      const: "show",
                                    },
                                  },
                                  required: ["someField"],
                                },
                              ],
                            },
                          ],
                        },
                      },
                    },
                  },
                ],
              },
            },
            label: "Some object",
          },
        ],
      },
    ],
  }

In JSON Forms, these rules are evaluated against the most inner scope, so in this case against the array.items data which is modeled like this

{
  type: "object",
  required: [],
  properties: {
    someObjectField: {
      title: "object field",
      type: "string",
    },
  },
},

The rule therefore can never apply and therefore the control is never shown.

We currently don’t support referring to parent scopes like the root schema in rules, see Reference a property outside of the array · Issue #2094 · eclipsesource/jsonforms · GitHub

In your custom code you evaluate the rule yourself but then you dispatch back to default JSON Forms dispatch. This default JSON Forms dispatch will then again find this rule, evaluate to false and therefore hide itself.


The regular array renderer (list-style) which you are using has no issues with hiding/showing nested elements. Therefore you don’t need to customize the regular array renderer.

Instead you can either use:

  • The new programmatic rules, see here. They do not even have the scope limitation, i.e. they are able to access the full data in addition to the scoped one, OR
  • if you want to go the declarative route, then you need to customize all the controls which are to be rendered WITHIN the array layout renderer, e.g. string renderer, enum renderer etc. to enhance their rule evaluation to cover your needs.

If altogether you wanted to customize the array table rendering and not the array layout rendering, then you need to copy not the MaterialArrayLayoutRenderer but the MaterialArrayControlRenderer

There you need the customization if you want specific cells in the table to be able to be shown/hidden via rules as we do not support UI Schemas for table details and therefore have no rule support for them