angular: I can't create dynamic FormGroup manually

๐Ÿž bug report

Affected Package

The issue is caused by package @angular/....

Is this a regression?

Yes, the previous version in which this bug was not present was: ....

Description

this code not work fine at first time page load and fire exception

๐Ÿ”ฌ Minimal Reproduction

component.ts



    this.contactForm = new FormGroup({
      name: new FormControl(),
       phones: new FormArray([new FormGroup({Phone: new FormControl('')})])
         });


component.html

<div formArrayName="phones">
            <div *ngFor="let item of phones.controls; let phoneIndex = index" [formGroupName]="phoneIndex">
                <label>
                    Phone: <input formControlName="phone" />
                </label>
                <button type="button" (click)="deletePhone(phoneIndex)">Delete Phone</button>
            </div>
            <button type="button" (click)="addPhone()">Add Phone</button>
        </div>

๐Ÿ”ฅ Exception or Error



Cannot find control with path: 'phones -> 0 -> phone'

๐ŸŒ Your Environment

Angular CLI: 8.3.23 Node: 12.14.1 OS: win32 x64

Anything else relevant? if I used formbuilder, it will work fine


 this.contactForm = this.fb.group({
      name: '',
      address: '',
      note: '',
      phones: this.fb.array([this.fb.group({phone:''})])
    });

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 7
  • Comments: 16 (2 by maintainers)

Most upvoted comments

See related bug report for Chrome 80 https://bugs.chromium.org/p/chromium/issues/detail?id=1049982 - _find method in forms.js uses Array.reduce

We totally have this same issue. We were alerted to it when testing in Chrome 80 Beta. The issue appears to be within the the _find function on the AbstractControl that is called withing the get(path: Array<string | number> | string) function. In that _find function it appears to break down in the .reduce.

function _find(control: AbstractControl, path: Array<string|number>| string, delimiter: string) {
  if (path == null) return null;

  if (!(path instanceof Array)) {
    path = (<string>path).split(delimiter);
  }
  if (path instanceof Array && (path.length === 0)) return null;

  return (<Array<string|number>>path).reduce((v: AbstractControl | null, name) => {
    if (v instanceof FormGroup) {
      return v.controls.hasOwnProperty(name as string) ? v.controls[name] : null;
    }

    if (v instanceof FormArray) {
      return v.at(<number>name) || null;
    }

    return null;
  }, control);
}

Through some other testing I could prove that using this.form.get(โ€˜xcontrolโ€™) would return null, but if we called this.form.controls[โ€˜xcontrolโ€™] it is present.

Unfortunately from the html it is not possible to control how the directives get the controls. We were able to work around it creating an explicit formGroup instead of relying on formGroupName to create the formGroup. An example with your code would be:

<div formArrayName="phones">
            <div *ngFor="let item of phones.controls; let phoneIndex = index" [formGroup]="phones.controls[phoneIndex]">
                <label>
                    Phone: <input formControlName="phone" />
                </label>
                <button type="button" (click)="deletePhone(phoneIndex)">Delete Phone</button>
            </div>
            <button type="button" (click)="addPhone()">Add Phone</button>
        </div>

Honestly, I feel like the issue is really a Chrome 80 issue, almost like a rendering problem. However, our app is too complicated to use to submit a bug to the chromium team, and I canโ€™t reproduce it out of the context of our app. I am glad to see others are experiencing this also.

https://github.com/angular/angular/pull/35349 landed, so weโ€™ll have a new Angular patch version that we can use that does not rely on Array.reduce (while we are waitin for the next Chrome version that should fix the underlying issue).

@MuhammadAbdelsalam i think it becuase you use incorrect name when you use in template you use <input formControlName="phone" /> (it phone in all small case) but in component you use new FormGroup({Phone: new FormControl('')}) (it Phone with capital letter) that is why you can use form builder and it work fine. becuase in form builder you use phone

We have similar issue with Chrome 80.

Error: formGroup expects a FormGroup instance. Please pass one in.

The error message is different but I think root cause is same. This is the code link. https://stackblitz.com/edit/angular-8exdsq

When we update angular to 9, the problem less likely to occur. But if we increase FormGroup, the problem occurs again.

We are having the same issue with Chrome 80 when trying to load several of our Reactive forms.

Error: Cannot find control with name: โ€˜nameOfControlโ€™

where nameOfControl is the first formControl on the form or the first to be referenced in TypeScript after creating the FormGroup. Chrome 79 and earlier, IE, Edge, and Firefox all work as expected.

I tried upgrading angular to the latest, 8.2.14 from an earlier 8.2.x revision and that made no difference.