json-schema-form/angular-schema-form

Data Model Nested Arrays

dlodeprojuicer opened this issue · 11 comments

I am trying to display an array item inside an array item, on the first level array i can select items to display but when I try the same thing on the nested array it does not display the fields in an array and the data model creates an object instead of array

Schema
"Questions": {
  "type": "array",
  "title":"Create Entity Properties", 
  "items": {
    "type": "object",
    "title": "Question",
    "properties": {
      "keyOne": {
        "title": "First Level Question",
        "type": "string",
        "required": true
      },
      "nestedQuestions": {
        "type": "array",
        "title":"Nested Title", 
        "items": {
          "type": "object",
          "title": "Question",
          "properties": {
            "keyTwo": {
              "title": "Second Level Question",
              "type": "string",
              "required": true
            },
            "keyThree": {
              "title": "Question",
              "type": "string",
              "required": true
            }
          }
        }
      }
    }
  }
}
Layout
[
 "Questions[].keyOne",
"Questions[].nestedQuestions[].keyTwo"
]
data model output
{
  "Questions": [
    {
      "keyOne":"User put",
      "nestedQuestions": {
        "0": {
          "keyTwo": "Filed Two User Input"
        }
      }
    }
  ]
}

Expected output
{
  "Questions": [
    {
      "keyOne":"User put",
      "nestedQuestions": [
        {
          "keyTwo": "Filed Two User Input"
        }
      ]
    }
  ]
}

Data model seems right if i don't get specific after Question[].nestedQuestion, seems to be breaking when i select a specific field Question[].nestedQuestion.keyTwo. What is the best way to get the _Expected output_ ?

Thanks

Uhmmm... is "data model output" and "Expected output" above supposed to be the same? If so I don't understand how it breaks?

According to schema, expected would be an array in nestedQuestions and not object with key "0".

Sorry that is a typo.. I updated _Expected output_

@fiddur correct, it only creates an array when I display everything in nestedQuestions like so "Questions[].nestedQuestions"

It's the form definition thats the culprit, when handling parts of arrays you still need to define the array in the form and give it a items property with it's children.

Try this form definition, it worked for me :)

[
 {
    "key": "Questions",
    "items": [
        "Questions[].keyOne",
        {
            "key": "Questions[].nestedQuestions",
            "items": ["Questions[].nestedQuestions[].keyTwo"]
        }
    ]
 }
]

Ahh yes! I see. However the data model shows

"nestedQuestions": {
        "0": {
          "keyOne": "Embedded Entity"
        }
      }

instead of

"nestedQuestions": [
{
          "keyOne": "User Input"
        }
      ]

Thank you!!

No problem :-)

Was there actually a resolution to this issue? I'm having the exact same issue with nested tabarrays.

On the first tab, everything works as expected. On tabs 2 and on, the nested array is registered as an object rather than array. It also produces the following error:

TypeError: list.push is not a function
at Scope.link.scope.$watch.scope.appendToArray

http://schemaform.io/examples/bootstrap-example.html#/b872c4fcad3517db964f

Any thoughts?

Form

[
  {
    "key": "items",
    "type": "tabarray",
    "tabType": "top",
    "add": "New",
    "remove": "Remove Item",
    "style": {
      "add": "btn-success",
      "remove": "button secondary"
    },
    "title": "{{value.location ? value.location : \"Tab \"+$index}}",
    "items": [
      "items[].access-token",
      "items[].base-url",
      "items[].client-secret",
      "items[].client-token",
      "items[].location",
      {
        "type": "fieldset",
        "title": "CP Codes",
        "items": [
          {
            "type": "tabarray",
            "key": "items[].cpCodeList",
            "title": "{{value.cpCode ? value.cpCode : \"CP Code \"}}",
            "add": "New",
            "remove": "Remove CP Code",
            "style": {
              "remove": "button secondary"
            },
            "items": [
              "items[].cpCodeList[].input",
              "items[].cpCodeList[].output",
              "items[].cpCodeList[].isSecure",
              "items[].cpCodeList[].isReflector",
              "items[].cpCodeList[].cpCode"
            ]
          }
        ]
      }
    ]
  }
]

Schema

{
  "type": "object",
  "title": "My Title",
  "required": [
  ],
  "properties": {
    "items": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "access-token": {
            "title": "Access Token",
            "type": "string",
            "maxLength": 128,
            "validationMessage": "Max length is {{schema.maxLength}}"
          },
          "base-url": {
            "title": "Base URL",
            "type": "string",
            "pattern": "",
            "maxLength": 128,
            "validationMessage": "Max length is {{schema.maxLength}}"
          },
          "client-secret": {
            "title": "Client Secret",
            "type": "string",
            "maxLength": 128,
            "validationMessage": "Max length is {{schema.maxLength}}"
          },
          "client-token": {
            "title": "Client Token",
            "type": "string",
            "maxLength": 128,
            "validationMessage": "Max length is {{schema.maxLength}}"
          },
          "location": {
            "title": "Location",
            "type": "string",
            "maxLength": 128,
            "validationMessage": "Max length is {{schema.maxLength}}"
          },
          "cpCodeList": {
            "title": "CP Code List",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "input": {
                  "title": "Input",
                  "type": "string",
                  "default": "tst"
                },
                "output": {
                  "title": "Output",
                  "type": "string"
                },
                "isSecure": {
                  "title": "Is Secure",
                  "type": "boolean"
                },
                "isReflector": {
                  "title": "Is Reflector",
                  "type": "boolean"
                },
                "cpCode": {
                  "title": "CP Code",
                  "type": "string"
                }
              },
              "required": [
                "input",
                "output",
                "cpCode"
              ]
            }
          }
        },
        "required": [
          "access-token",
          "base-url",
          "client-secret",
          "client-token",
          "location"
        ]
      }
    }
  }
}

The fix seems to be adding

"default": []

to your nested array as shown in the example below.

Example Schema

{
  "type": "object",
  "title": "My Title",
  "required": [
  ],
  "properties": {
    "items": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "propOne": {
            "title": "Prop One",
            "type": "string",
            "maxLength": 128,
            "validationMessage": "Max length is {{schema.maxLength}}"
          },
          "propTwo": {
            "title": "Prop Two",
            "type": "string",
            "maxLength": 128,
            "validationMessage": "Max length is {{schema.maxLength}}"
          },
          "nestedArray": {
            "title": "Nested Array",
            "type": "array",
            "default": [],
            "items": {
              "type": "object",
              "properties": {
                "nestedPropOne": {
                  "title": "Nested Prop One",
                  "type": "string"
                },
                "nestedPropTwo": {
                  "title": "Nested Prop Two",
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  }
}

@mbugbee +1 and kudos to your solution!

Kudos to @mbugbee for the solution as well. For me this error started happening only when adding a boolean to a nested array. It worked fine if the nested array contained string/number fields. As soon as I would add a boolean field, I got a "s.push is not a function" error. Your solution of adding the default empty array solved it.