Search code examples
angulartypescriptangular-reactive-forms

How to initialize angular reactive form with different key values


I am trying to build angular form with given key names and values of that keys that are always the same. I have managed to build one form but output format is not quite the one I need.

keysToChange = ['key1', 'key2', 'key3', 'key4']

export interface PatchForm {
  [x: string]: FormControl<string | null>
  date: FormControl<string | null>
}

patchForm = this.fb.group({
  keysToChange: this.fb.array<FormGroup<PatchForm>>([]),
})

  initializeForm() {
    this.keysToChange.forEach((key) => {
      const formGroup = this.fb.nonNullable.group({
        [key]: new FormControl(''),
        date: new FormControl(''),
      })
      this.patchForm.controls.keysToChange.push(formGroup)
    })
  }

I get this output:

{
    "keysToChange": [
        {
            "key1": "",
            "date": ""
        },
        {
            "key2": "",
            "date": ""
        },
        {
            "key3": "",
            "date": ""
        },
        {
            "key4": "",
            "date": ""
        }
    ]
}

but I need more something like this:

export interface PatchForm {
  id: FormControl<string | null>
  date: FormControl<string | null>
}

then output like this:

{
  "key1": {
    "id": "string",
    "date": "2024-04-03T11:23:05.499Z"
  },
  "key2": {
    "id": "string",
    "date": "2024-04-03T11:23:05.499Z"
  },
  "key3": {
    "id": "string",
    "date": "2024-04-03T11:23:05.499Z"
  },
  "key4": {
    "id": "string",
    "date": "2024-04-03T11:23:05.499Z"
  }
}

problem I have is mainly creating types and initializing form because my eslint is not allowing unsafe use of type 'any' and I don't quite understand how to initialize keys for each FormGroup.


Solution

  • We need to create a formGroup and then use addControl to add each individual control with the key name and formgroup. Please find below working example, let me know if any doubts!

    import { CommonModule } from '@angular/common';
    import { Component, inject } from '@angular/core';
    import {
      FormBuilder,
      FormControl,
      FormGroup,
      ReactiveFormsModule,
    } from '@angular/forms';
    import { bootstrapApplication } from '@angular/platform-browser';
    import 'zone.js';
    
    export interface PatchForm {
      [x: string]: FormControl<string | null>;
      date: FormControl<string | null>;
    }
    
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [ReactiveFormsModule, CommonModule],
      template: `
        <form [formGroup]="patchForm">
          <div formGroupName="keysToChange">
            <div *ngFor="let item of iterKeys; let i = index" [formGroupName]="item">
              <input type="text" formControlName="id" id="id" name="id"/>
              <input type="date" formControlName="date" id="date" name="date"/>
            </div>
          </div>
        </form>
        {{patchForm.value | json}}
      `,
    })
    export class App {
      keysToChange = ['key1', 'key2', 'key3', 'key4'];
      name = 'Angular';
      fb = inject(FormBuilder);
      iterKeys: Array<string> = [];
    
      patchForm = this.fb.group({
        keysToChange: this.fb.group({}),
      });
    
      ngOnInit() {
        this.initializeForm();
      }
    
      initializeForm() {
        this.keysToChange.forEach((key) => {
          const formGroup = this.fb.nonNullable.group({
            id: new FormControl(''),
            date: new FormControl(''),
          });
          this.patchForm.controls.keysToChange.addControl(key, formGroup);
        });
        this.iterKeys = Object.keys(this.patchForm.controls.keysToChange.controls);
      }
    }
    
    bootstrapApplication(App);
    

    Stackblitz Demo