angularangular-formsformarrayangular15angular2-formbuilder

Cannot find control with path error after migrating to Angular 15


The migration from Angular 10 to Angular 15 has caused the following error on the console:

ERROR Error: Cannot find control with path: 'mappedHeaders -> 0 -> value'

example.ts

headerArray: FormArray;
formGroup: FormGroup;

constructor(private fb: FormBuilder) {
    this.headerArray = this.fb.array([]);
    this.formGroup = this.fb.group({
      mappedHeaders: this.headerArray
    });
  }

printing the structure of this.headerArray on the console post initilization:

form array first element

printing the structure of this.formGroup on the console after pushing the values: formGroup.controls

example.html:

   <div [formGroup]="formGroup">
    <table>
      <tbody formArrayName="mappedHeaders">
      <ng-container *ngFor="let header of accountHeaders; index as i">
        <tr>
          <td>{{i}}</td>
          <td [formGroupName]="i">
            <select class="ui fluid clearable selection search dropdown column-mapping-dropdown" formControlName="value">
              <option *ngFor="let header of fileHeaders" [value]="header">{{ header }}</option>
            </select>
          </td>
        </tr>
      </ng-container>
      </tbody>
    </table>
  </div>

the accountHeaders is an array of strings like ['one', 'two', 'three',...'etc']

The above code works perfectly as expected in Angular 10. I have checked other similar issues but none could address this.

Update The controls are pushed into array post a network call:

const mapped = result['mappedHeaders'];
      for (const accountHeader of this.accountHeaders.sort()) {
        this.headerArray.push(this.fb.control({
          key: accountHeader,
          value: mapped[accountHeader]
        }));
      }

mapped is a map of key value like ['one': 'one', 'two': 'three']


Solution

  • combining the answers given by @Naren and @Eliseo, the below modification to the code resolved the issue.

    1 - The iteration must happen on the formArray controls:

      get formArrayControls() {
        const formArray = this.formGroup.get('mappedHeaders') as FormArray;
        return formArray.controls;
    }
    

    and

    <ng-container *ngFor="let header of formArrayControls; index as i">
    

    2 - I was pushing formControls into mappedHeaders array instead of formGroups. Therefore, I created a method that adds the elements to the array:

      addToFormArray(key: string, value: string) {
        let formArray = this.formGroup.get('mappedHeaders') as FormArray;
        formArray.push(this.fb.group({
          key: [key],
          value: [value]
        }));
      }
    

    and call the function as follows:

      for (const accountHeader of this.accountHeaders.sort()) {
        this.addToFormArray(accountHeader, mapped[accountHeader]);
      }