angulartypescriptangular-reactive-formsangular18

Using Angular 18, how can I have a Reactive Form with an Array of Text Form Controls?


In my Angular component, I have a Foo with a property bar which is an array of strings.

I want to edit the list of text lines in my form. In my component, I declare

  barEditForm = new FormGroup({
    bar: new FormArray<FormControl>([])
  });

I then initialise my form from the Foo I have loaded.

  foo.bar.forEach((bar: string) => {
    this.barEditForm.controls.bar.push(new FormControl(bar));
  });

How do I create a form with an input for each bar in my HTML template.

This;

  <form [formGroup]="barEditForm" (ngSubmit)="onBarSave(foo.id)">
    @for (bar of barEditForm.controls.bar.controls; track $index) {
      <input class="form-control" id="bar" type="text" formControlName="$index"/>
    }
  </form>

does not work!

I assume, I need to iterate over my created controls, hence the for of barEditForm.controls.bar.controls.

I also assume I can use $index as the form control name.

But, I get an error of ERROR TypeError: e is null and an empty text input.

What is the correct way to do this?


Solution

  • You have to define formArrayName as bar, then define the formControlName with property binding.

    <form [formGroup]="barEditForm" (ngSubmit)="onBarSave(foo.id)">
        <div formArrayName="bar">
          @for (bar of barEditForm.controls.bar.controls; track $index) {
            <input class="form-control" [id]="'control' + $index" type="text" [formControlName]="$index"/>
        }
        </div>
      </form>
    

    Another option is to use formControl with property binding which does not use $index

    <form [formGroup]="barEditForm" (ngSubmit)="onBarSave(foo.id)">
        <div formArrayName="bar">
          @for (control of barEditForm.controls.bar.controls; track $index) {
            <input class="form-control" [id]="'control' + $index" type="text" [formControl]="control"/>
        }
        </div>
      </form>