Help - please: Nesting multiple arrays in order to create dynamically growing form

Greetings, first off, awesome tool! Really really awesome I like it so much!

However, I have a very specific use case. I would like to build a form with the “array” type that can be expanded like I currently have. Currently it is really nice working but I seem to totalls struggle to nest the “array” type within it. I would like to generate new “vizualizationOptions” for an “attribute”. So currently you can create attributes and fill in their field but one attribute can have multiple “visualizationOptions”. Furthermore even then inside an option should be more groups.

I hope you can give me an example or idea. Currently it looks like this:

However you see there no applicable renderer found. My scheme looks like this:

{
  "properties": {
    "attributes": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "description": "The id of the measurement, e.g. \"battery\"."
          },
          "label": {
            "title": "Label",
            "type": "string",
            "description": "The unique label of the measurement, e.g. \"Battery Level\"."
          },
          "attributeType": {
            "title": "Attribute Type",
            "type": "string",
            "oneOf": [
              {
                "const": "null",
                "title": "None"
              },
              {
                "const": "nominal",
                "title": "Nominal"
              },
              {
                "const": "binary",
                "title": "Binary"
              },
              {
                "const": "ordinal",
                "title": "Ordinal"
              },
              {
                "const": "discrete",
                "title": "Discrete"
              },
              {
                "const": "continuous",
                "title": "Continuous"
              }             
            ],
            "description": "The attribute type of the measurement. Can also be \"null\"."
          },
          "unit": {
            "title": "Unit",
            "type": "string",
            "description": "The unit of the measurement as a string."
          },
          "min": {
            "title": "Min",
            "type": "number",
            "description": "The minimum expected value of the measurement as a number."
          },
          "max": {
            "title": "Max",
            "type": "number",
            "description": "The maximum expected value of the measurement as a number."
          },
          "visualizationOptions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "title": "Type"
                }
              }
            }
          }
        },
        "required": [
          "id",
          "label",
          "attributeType",
          "unit"
        ]
      }
    }
  }
}

and my ui scheme looks like this:

{
  "type": "VerticalLayout",
  "elements": [
    {
      "type": "Control",
      "scope": "#/properties/attributes",
      "options": {
        "showSortButtons": true,
        "elementLabelProp": "id",
        "detail": {
          "type": "VerticalLayout",
          "elements": [
            {
              "type": "HorizontalLayout",
              "elements": [
                {
                  "type": "Control",
                  "scope": "#/properties/id"
                },
                {
                  "type": "Control",
                  "scope": "#/properties/label",
                  "options": {
                    "multi": true
                  }
                }
              ]
            },
            {
              "type": "Control",
              "scope": "#/properties/attributeType",
              "options": {
                "format": "radio"
              }
            },
            {
              "type": "Control",
              "scope": "#/properties/unit"
            },
            {
              "type": "HorizontalLayout",
              "elements": [
                {
                  "type": "Control",
                  "scope": "#/properties/min",
                  "options": {
                    "detail": "GENERATED"
                  }
                },
                {
                  "type": "Control",
                  "scope": "#/properties/max"
                }
              ]
            },
            {
              "type": "Control",
              "scope": "#properties/visualizationOptions",
              "options": {
                "showSortButtons": true,
                "elementLabelProp": "type",
                "detail": {
                  "type": "VerticalLayout",
                  "elements": [

                  ]
                }
              }
            }
          ]
        }
      }
    }
  ]
}

I hope you can help me! Thank you very much!

Hi @cubicmagnet,

Thanks for your compliments :wink:

JSON Forms supports arbitrary many levels of nesting, so there should be no problem of using arrays within arrays. Of course at some point the UI might be too complex to understand.

In your case there is just a slight typo in the scope of the nested array (a missing ‘/’), so using the following control for the visualizationOptions does the trick:

            {
              "type": "Control",
              "scope": "#/properties/visualizationOptions",
              "options": {
                "showSortButtons": true
              }
            }

Note that I also removed the empty detail option as this leads to an empty UI.

1 Like

OH NO!!! Such a dumb error from me :laughing:. I didn’t see that but glad you also answered my question if you can nest multiple ones. Anyway :laughing: that was dumb from me.

Really awesome tool you got there! Will use it now everytime I am making a from. Which is fairly often.

I would have a followup question. I am not sure if I am right here but maybe I am if not please tell me. How would I style then the elements inside the “style” group. Currently I was using the example https://jsonforms.io/examples/gen-uischema. However it doesn’t show how to style the “age” property. I would like to have multiple properties in my style but also align them in layouts. I am not sure how to do it.

Like styling these as radio ones:

My scheme looks like this:

{
  "properties": {
    "attributes": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "description": "The id of the measurement, e.g. \"battery\"."
          },
          "label": {
            "title": "Label",
            "type": "string",
            "description": "The unique label of the measurement, e.g. \"Battery Level\"."
          },
          "attributeType": {
            "title": "Attribute Type",
            "type": "string",
            "oneOf": [
              {
                "const": "null",
                "title": "None"
              },
              {
                "const": "nominal",
                "title": "Nominal"
              },
              {
                "const": "binary",
                "title": "Binary"
              },
              {
                "const": "ordinal",
                "title": "Ordinal"
              },
              {
                "const": "discrete",
                "title": "Discrete"
              },
              {
                "const": "continuous",
                "title": "Continuous"
              }             
            ],
            "description": "The attribute type of the measurement. Can also be \"null\"."
          },
          "unit": {
            "title": "Unit",
            "type": "string",
            "description": "The unit of the measurement as a string."
          },
          "min": {
            "title": "Min",
            "type": "number",
            "description": "The minimum expected value of the measurement as a number."
          },
          "max": {
            "title": "Max",
            "type": "number",
            "description": "The maximum expected value of the measurement as a number."
          },
          "visualizationOptions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "title": "Visualization Type",
                  "type": "string",
                  "oneOf": [
                    {
                      "const": "dot",
                      "title": "Dot"
                    },
                    {
                      "const": "bubble",
                      "title": "Bubble"
                    },
                    {
                      "const": "bar",
                      "title": "Bar"
                    },
                    {
                      "const": "box",
                      "title": "Box"
                    }           
                  ],
                  "description": "The visualization type for the current measurement."
                },
                "style": {
                  "type": "object",
                  "properties": {
                    "offset": {
                      "type": "string",
                      "oneOf": [
                        {
                          "const": "ground",
                          "title": "Ground"
                        },
                        {
                          "const": "altitude",
                          "title": "Altitude"
                        },
                        {
                          "const": "fixed",
                          "title": "Fixed"
                        }          
                      ],
                      "description": "TBD..."
                    },
                    "datumInterval": {
                      "type": "string",
                      "oneOf": [
                        {
                          "const": "lastValue",
                          "title": "Last Value"
                        },
                        {
                          "const": "dailySummary",
                          "title": "Daily Summary"
                        },
                        {
                          "const": "weeklySummary",
                          "title": "Weekly Summary"
                        },
                        {
                          "const": "yearlySummary",
                          "title": "Yearly Summary"
                        }              
                      ],
                      "description": "TBD..."
                    }
                  }
                }
              }
            }
          }
        },
        "required": [
        ]
      }
    }
  }
}

My ui scheme like this:

{
  "type": "VerticalLayout",
  "elements": [
    {
      "type": "Control",
      "scope": "#/properties/attributes",
      "options": {
        "showSortButtons": true,
        "elementLabelProp": "id",
        "detail": {
          "type": "VerticalLayout",
          "elements": [
            {
              "type": "HorizontalLayout",
              "elements": [
                {
                  "type": "Control",
                  "scope": "#/properties/id"
                },
                {
                  "type": "Control",
                  "scope": "#/properties/label",
                  "options": {
                    "multi": true
                  }
                }
              ]
            },
            {
              "type": "Control",
              "scope": "#/properties/attributeType",
              "options": {
                "format": "radio"
              }
            },
            {
              "type": "Control",
              "scope": "#/properties/unit"
            },
            {
              "type": "HorizontalLayout",
              "elements": [
                {
                  "type": "Control",
                  "scope": "#/properties/min",
                  "options": {
                    "detail": "GENERATED"
                  }
                },
                {
                  "type": "Control",
                  "scope": "#/properties/max"
                }
              ]
            },
            {
              "type": "Control",
              "scope": "#/properties/visualizationOptions",
              "options": {
                "showSortButtons": true,
                "elementLabelProp": "type",
                "detail": {
                  "type": "VerticalLayout",
                  "elements": [
                      {
                        "type": "Control",
                        "scope": "#/properties/type"
                      },
                      {
                        "type": "Control",
                        "scope": "#/properties/style"
                      }
                  ]
                }
              }
            }
          ]
        }
      }
    }
  ]
}

Thank you very much!

Hi @cubicmagnet,

You should be able to use another detail UI Schema like you already did for the visualizationOptions. Did you encounter any problem with that?