htmlangulartypescriptangular-reactive-formsformarray

How to create nested dynamic form elements


I want the select-option and input-text fields to be added once when I click on the Add button.

I've already achieved this. That's okay.

When I click on the Add Serv button, the input-text field in the relevant line needs to be added.

Now, every time I click, it assigns a field to each line. Once I click, there are 2 "Services" fields per row. When I click twice, there are 3 "Services" fields in each line.

When I click on the Remove Serv button, it deletes one row from each row, showing a similar behavior. How can I ensure that these operations occur for the relevant row?

The "Add serv" and "Remove serv" buttons are not working properly.

keyValueFA = new FormArray([this.newKeyValueFG]);
keyServFA = new FormArray([this.newServFG]);

propertyFG = new FormGroup({
  keyValue: this.keyValueFA,
  //serv:this.keyServFA
});


get newKeyValueFG(): FormGroup {
  return new FormGroup({
    prof: new FormControl(null),
    //serv: new FormControl(null),
  });
}

get newServFG(): FormGroup {
  return new FormGroup({
    serv: new FormControl(null),
  });
}

get keyValueArrayFGControls(): FormGroup[] {
  return this.keyValueFA.controls as FormGroup[];
}

get keyValueArrayFGControlss(): FormGroup[] {
  return this.keyServFA.controls as FormGroup[];
}

addNewKeyValueFG(): void {
  this.keyValueFA.push(this.newKeyValueFG);
}

addNewServFG(): void {
  this.keyServFA.push(this.newServFG);
}

removeNewKeyValueFG(index: number): void {
  this.keyValueFA.removeAt(index);
}

removeNewServFG(index: number): void {
  this.keyServFA.removeAt(index);
}
<form [formGroup]="propertyFG">
  <div formArrayName="keyValue" *ngFor="let fg of keyValueArrayFGControls; let i = index">
    <div [formGroup]="fg">

      <div class="col-4">

        <select formControlName="prof" width="100%" class="form-control">

          <option *ngFor="let l of professions;" [value]="l._id">
            {{getProfessionNameByLang(l.name)}}
          </option>
        </select>

      </div>

      <div *ngFor="let sr of keyValueArrayFGControlss; let j = index" class="col-4">
        <div [formGroup]="sr">

          <input type="text" formControlName="serv" [id]="'myDiv-' + i+ j" placeholder="Hizmet" />

          <button (click)="removeNewServFG(j)">Remove Serv</button>

        </div>

      </div>
      <button (click)="removeNewKeyValueFG(i)">Remove</button>
      <button (click)="addNewServFG()">Add Serv</button>

    </div>

  </div>

  <button (click)="addNewKeyValueFG()">Add</button>
</form>

enter image description here

enter image description here


Solution

  • You are sharing the same FormArray instance keyServFA for each FormGroup. Instead, each FormGroup should have its own keyServFA/services FormArray.

      <ng-container formArrayName="services">
        <div
          *ngFor="let sr of serviceControlsByKeyValueFG(i).controls; let j = index"
          class="col-4"
        >
          <div [formGroupName]="j">
            <input
              type="text"
              formControlName="serv"
              [id]="'myDiv-' + i+ j"
              placeholder="Hizmet"
            />
    
            <button (click)="removeNewServFG(i, j)">Remove Serv</button>
          </div>
        </div>
      </ng-container>
    
      <button (click)="removeNewKeyValueFG(i)">Remove</button>
      <button (click)="addNewServFG(i)">Add Serv</button>
    

    When adding, retrieving, or deleting the service FormGroup, you should provide the index of keyValueFG to get the correct keyValueFG FormGroup.

    get newKeyValueFG(): FormGroup {
      return new FormGroup({
        prof: new FormControl(null),
        services: new FormArray([this.newServFG]),
      });
    }
    
    serviceControlsByKeyValueFG(rootIndex: number): FormArray {
      return (this.keyValueFA.controls[rootIndex] as FormGroup).controls[
        'services'
      ] as FormArray;
    }
    
    addNewServFG(rootIndex: number): void {
      this.serviceControlsByKeyValueFG(rootIndex).push(this.newServFG);
    }
    
    removeNewServFG(rootIndex: number, index: number): void {
      this.serviceControlsByKeyValueFG(rootIndex).removeAt(index);
    }
    

    Demo @ StackBlitz