Unable to edit input fields when using formGroupName

63 Views Asked by At

This is how I set my form control:

formMain = this.fb.group({ 
  details: this.fb.array([
    new FormGroup({
      label: new FormControl(''),
      description: new FormControl(''),
    })
  ])
});

My HTML has some dynamic input fields:

<div formArrayName="details">
  <div *ngFor="let detail of formMain.value.details; index as i">
    <mat-form-field appearance="fill">
      <mat-label>Label of a detail</mat-label>
      <input id="detail-label" matInput type="text" [value]="detail.label">
    </mat-form-field>

    <mat-form-field appearance="fill">
      <mat-label>Description of a detail</mat-label>
      <input id="detail-description" matInput type="text" [value]="detail.description">
    </mat-form-field>
  </div>
</div>

This works fine. So if the form controls include values, they will be passed to the values of the input fields. I can edit these values, however, the new values will not be stored in the form control. This may be because I am not using formControlName.

This is how I added formControlName and also [formGroupName]="i":

<div *ngFor="let detail of formMain.value.details; index as i" [formGroupName]="i">
  <mat-form-field appearance="fill">
    <mat-label>Label of a detail</mat-label>
    <input id="detail-label" matInput type="text" [value]="detail.label" formControlName="label">
  </mat-form-field>
...

I receive no errors but I am no longer able to edit the values of the input fields. Neither I can't focus the input field with the mouse or even mark the values. The input fields are completely locked. This is what I see in the DOM:

<div class="mat-form-field-infix ng-tns-c97-1030"><input _ngcontent-lqv-c198="" id="detail-label" matinput="" type="text" formcontrolname="label" class="mat-input-element mat-form-field-autofill-control ng-tns-c97-1030 ng-untouched ng-pristine ng-valid cdk-text-field-autofill-monitored" ng-reflect-name="label" ng-reflect-id="detail-label" ng-reflect-type="text" ng-reflect-value="Brooklyn" aria-invalid="false" aria-required="false"><span class="mat-form-field-label-wrapper ng-tns-c97-1030"><label class="mat-form-field-label ng-tns-c97-1030 ng-star-inserted" ng-reflect-disabled="true" id="mat-form-field-label-2045" ng-reflect-ng-switch="true" for="detail-label" aria-owns="detail-label"><!--bindings={
  "ng-reflect-ng-switch-case": "false"
}--><mat-label _ngcontent-lqv-c198="" class="ng-tns-c97-1030 ng-star-inserted">Label of a detail</mat-label><!--bindings={
  "ng-reflect-ng-switch-case": "true"
}--><!--bindings={
  "ng-reflect-ng-if": "false"
}--></label><!--bindings={
  "ng-reflect-ng-if": "true"
}--></span></div>

This happens because of [formGroupName]="i". If I remove that, I can edit the values of the input field but then I receive the error:

ERROR Error: Cannot find control with path: 'details -> label'

How do I fix this?

1

There are 1 best solutions below

2
On BEST ANSWER

You should loop the form controls of the details FormArray instead of the objects in the details array in the *ngFor.

And you don't need to supply the [value] attribute as when applying the formControlName attribute, the input field will be bound with value.

<div
  *ngFor="let detail of detailsFormArray.controls; index as i"
  [formGroupName]="i"
>
  <mat-form-field appearance="fill">
    <mat-label>Label of a detail</mat-label>
    <input id="detail-label" matInput type="text" formControlName="label" />
  </mat-form-field>

  <mat-form-field appearance="fill">
    <mat-label>Description of a detail</mat-label>
    <input
      id="detail-description"
      matInput
      type="text"
      formControlName="description"
    />
  </mat-form-field>
</div>
get detailsFormArray() {
  return this.formMain.controls.details as FormArray;
}

Demo @ StackBlitz

Reference: Angular FormArray: Complete Guide