verizonconnect / ngx-form-generator

Generate Angular ReactiveForms from OpenAPI documents
MIT License
44 stars 13 forks source link

Support for FormArray #28

Open tommie822 opened 2 years ago

tommie822 commented 2 years ago

It would be nice to let Open Api Specification arrays map to the Angular FormArray. As it makes creating forms with arrays more easier.

I would like to implement it but i'm curious if you have a specific reason why it isn't currently implemented.

martinmcwhorter commented 2 years ago

I am happy to help craft a PR for this.

Can you provide me an example open-api doc and what you would expect the form to look like for this?

Arberto99 commented 2 years ago

Thanks a lot! It would be amazing!

For this open-api doc:

"ReadResourceDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "NestedResource": {
            "$ref": "#/components/schemas/NestedResourceDto"
          },
          "NestedResourceArray": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NestedResourceArrayDto"
            }
          },
        },
        "required": [
          "id",
          "name",
          "NestedResource",
          "NestedResourceArray",
        ]
},

"NestedResourceArrayDto": {
    "type": "object",
    "properties": {
        "id": {
           "type": "string",
           "format": "uuid"
         },
         "name": {
           "type": "string"
          }
    },
    "required": [
          "id",
          "name"
    ]
},

"NestedResourceDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ]
},

Right now, the generated code is this:

export const ReadResourceDtoForm = new FormGroup({
  id: new FormControl(null, [Validators.required]),
  name: new FormControl(null, [Validators.required]),
  description: new FormControl(null),
  NestedResource: new FormControl(null, [Validators.required]),
  NestedResourceArray: new FormControl(null, [Validators.required]),
});

But it would be expected something like this:

export const readApplicationDtoForm = new FormGroup({
  id: new FormControl(null, [Validators.required]),
  name: new FormControl(null, [Validators.required]),
  description: new FormControl(null),
  NestedResource: new FormGroup({
      id: new FormControl(null, [Validators.required]),
      name: new FormControl(null, [Validators.required]),
  }),
  NestedResourceArray: new FormArray(
  ...
  ),
});

If you need any help for development I'll be glad to help you.

Thanks a lot!

RoRep1ay commented 2 years ago

Hey @Arberto99 , I did a bit drafting related to supporting form array and nested form group, though I'm not quite sure how we construct FormArray in this case.

From your API spec:

          "NestedResourceArray": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NestedResourceArrayDto"
            }
          },

What would be expected result here?

  NestedResourceArray: new FormArray(
  ...
  ),
Arberto99 commented 2 years ago

Hi @RoRep1ay ! Thanks for your answer!

The result should be something like this:

NestedResourceArray: new FormArray([
    new FormGroup(
          id: new FormControl(null, [Validators.required]),
          name: new FormControl(null, [Validators.required]),
    )
])

What do you think about it? It sounds good to me, but I'm ready to listen some alternative solutions.

Thanks again anyway!

RoRep1ay commented 2 years ago

Hi @Arberto99 ,

I'm OK with your proposal, though there is still one small details that we haven't discussed yet, which is related to minItems and maxItems. What's your opinion to it?

To me, I prefer to ignore maxItems spec, for minItems, we generate formarray with array values the same as the minItems value.

Ex:

definitions:
  FooModel:
    type: object
    properties:
      foo:
        type: array
        minItems: 3
        maxItems: 10
        items:
          type: string
          minLength: 1

Output:


foo = new FormArray([
  new FormControl(null, Validators.minLength(1))
  new FormControl(null, Validators.minLength(1))
  new FormControl(null, Validators.minLength(1))
])
Arberto99 commented 2 years ago

Yes, I'm ok with it.

martinmcwhorter commented 2 years ago

Alright. This is really becoming clearer to me now on how this can be done. Discussion like this really does help.

RoRep1ay commented 2 years ago

@martinmcwhorter , if you're OK with the spec now, may I take over this issue?

martinmcwhorter commented 2 years ago

Absolutely. Take a stab at it and make a PR.