Search code examples
angulardata-bindingformarray

What's the best way to add/remove dynamically Form Array item?


Here's how I bind data received from an API to my Form Group/Array, on the CTOR:

  this.api.getRecipe(id).subscribe((data) => {
    this.form = this.fb.group({
      nome: [data.nome, [Validators.required]],
      ingredienti: this.fb.group({
        acqua: [data.ingredienti.acqua, [Validators.required]],
        farine: this.fb.array(
          data.ingredienti.farine.map(item => (
            this.fb.group({
              quantita: [item.quantita, [Validators.required]],
              nome: [item.nome]
            })
          ))
        )
      })
    });
  });

And this is how I iterate FormArray's farine items on View:

  <mat-card *ngFor="let item of form.get('ingredienti').get('farine')['controls']; let itemIndex = index">
    <div [formGroupName]="itemIndex">
      <mat-form-field>
        <input matInput type="number" formControlName="quantita" />
      </mat-form-field>
      <mat-form-field>
        <input matInput type="text" formControlName="nome" />
      </mat-form-field>
    </div>
    <button type="button" (click)="addFarina()">Add</button>
  </mat-card>     

Now, clicking on addFarina(), I'd like to simply add a new item on FormArray's farine. I did this:

  addFarina() {
    let farineForm = this.form.value.ingredienti.farine;
    let farineFormControls = this.form.get('ingredienti').get('farine')['controls'];

    if (farineForm.length < 4) {
      const farina = this.fb.group({
        quantita: [null, [Validators.required]],
        nome: ['']
      })

      farineForm.push(farina);
      farineFormControls.push(farina);
    }
  } 

But I feel like I'm not really using the potentially of this framework, updating manually both this.form items and related farine's controls.

What's the best way to "edit" the data on form and subscribe edits also on View? So I don't need to manually manage the link between Data and View.


Solution

  • You should call push method on formArray control. Since you are pushing new FormGroup inside normal array underlaying FormGroup is not get updated.

        addFarina() {
            let farineForm = this.form.value.ingredienti.farine;
            let farineFormControls = this.form.get('ingredienti').get('farine') as FormArray;
        
            if (farineForm.length < 4) {
              const farina = this.fb.group({
                quantita: [null, [Validators.required]],
                nome: ['']
              })
        
              farineFormControls.push(farina);
            }
            console.log(this.form.get('ingredienti').value);
          } 
    

    Now you should be able to access all formValue like this no need to push values inside array manually.

    this.api.addRecipe(this.form.value).subscribe(...)
    

    Working Stackblitz