Angular. FormArray. Cannot find control with path: 'jobs -> 0 -> name'

Viewed 79

I have a form that's initialized in the component's constructor:

constructor(
private fb: FormBuilder,
 ) {
    this.form = this.fb.group({
      practice: [''],
      jobs: this.fb.array([
        this.fb.group({
          name: ['', [Validators.required]],
          dateRange: [{startDate: null, endDate: null}, [Validators.required]],
        }),
      ]),
    });
  }

And it's value is set like this:

@Input() set profile(newValue: Partial<FormModel>) {
  this.form.patchValue(newValue);

  if (value?.jobs.length) {
    this.form.setControl('jobs', this.fb.array(newValue.jobs));
  }
}

If newValue has more than one element in 'jobs', patchValue sets only one of them, because only one element is declared in constructor. That's why I also added setControl, and it seems to work fine - when I output this.form.value, it's value is identical to newValue. BUT I have troubles with displaying it in the template. That's how my html looks like:

<nz-form-control formArrayName="jobs">
  <ng-container
    *ngFor="let job of form.get('jobs').controls; let i=index"
    [formGroupName]="i"
  >
    <input formControlName="name"/>
    <app-range-datepicker
      formControlName="dateRange"
    ></app-range-datepicker>
  </ng-container>
</nz-form-control>

And I get errors in the console for every control (in case of 2 jobs):

Cannot find control with path: 'jobs -> 0 -> name'

Cannot find control with path: 'jobs -> 0 -> dateRange'

Cannot find control with path: 'jobs -> 1 -> name'

Cannot find control with path: 'jobs -> 1 -> dateRange'

(at setUpControl, at FormGroupDirective.addControl)

1 Answers

FormArray's can be a little tricky... and the Angular docs about it don't tell you explicitly about its element peculiarities.

You will need to build the FormArray element within the form Formgroup every time you add/remove items, as the patchValue call at the parent form would not know how do it.

The usual way to do it is to create a method to build the FormArray for you, something like this would work to add items:


addJob() {
  const formArray = <FormArray>this.form.get('jobs');
  formArray.push(
     this.fb.group({
          name: ['', [Validators.required]],
          dateRange: [{startDate: null, endDate: null}, [Validators.required]],
     })
   )
}

For the initial value, you would need to create the array from the initial values, from the constructor:

constructor(
private fb: FormBuilder,
 ) {
    this.form = this.fb.group({
      practice: [''],
      jobs: this.fb.array([]),
    });
    
    const formArray = <FormArray>this.form.get('jobs');
    this.initialValues.forEach(value => { // <-- might have to test if "this.initialValues" is null here, I am also assuming this is an array
       formArray.push(
          this.fb.group({
                 name: [value.name, [Validators.required]],
                 dateRange: [{startDate: value.startDate, endDate: value.endDate}, Validators.required]], // <- I am assuming the value shape here... but I think you got the gist of it
                 })
       );
    });
  }
Related