0

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 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

2 Comments

For some reasons this.formMain.controls.details; didn't work for me but I changed it to this.formMain.controls['details']. It works great. Thank you so much!
Ya, I forgot which Angular version to allow this.formMain.controls.details works. Your method works or it can also be: this.formMain.get("details").

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.