David
David

Reputation: 3614

Reactive form Angular breaks when updating an ArrayForm

I have a problem using a reactive form in an Angular app. I managed to isolate the problem in a Plunkr.

https://plnkr.co/edit/KiTHcaaZZA6kwDI0sfeR?p=preview

What I have is a form with an ArrayForm section where I can add rows with a button. Every one of these rows has many input fields, and a few of them display the result of other fields. For example, in my plunkr I have a MAX and a MIN button, which are numbers, and when both of them have a value, I need to update the value of another field, called TOTAL.

So this is the html template:

<form [formGroup]="form">
  <div>
  <input type="text" formControlName="client" placeholder="client">
  </div>

  <button type="button" (click)="addPublisher()">Add Publisher</button>

  <div formArrayName="publishers">
    <div *ngFor="let item of publishers; let i = index;">
      <div [formGroupName]="i">
        <input type="number" formControlName="max" placeholder="max">
        <input type="number" formControlName="min" placeholder="min">
        <input type="text" formControlName="total" placeholder="total">
      </div>
    </div>
  </div>

</form>

And this is the ts that matters. I'm subscribing to changes in the publishers, and updating the row only if the change is other than a row being added or deleted.

ngOnInit() {
    (this.form.get('publishers') as FormArray).valueChanges
      .map((publishers: any[]) => {
        if (this.totalPublishers === publishers.length) {
          publishers.forEach((publisher, index) => {
            console.log(`update publishers ${index}`);
            this.updatePublisher((this.form.get('publishers') as FormArray).get([index]) as FormGroup);
          });
        } else {
          console.log(`update total from ${this.totalPublishers} to ${publishers.length}`);
          this.totalPublishers = publishers.length;
        }
      })
      .subscribe();
  }

And to update the value, I do this

private updatePublisher(publisher: FormGroup) {
    this.updateTotals(publisher);
  }

  private updateTotals(publisher: FormGroup) {
    const max = publisher.get('max').value;
    const min = publisher.get('min').value;
    if (max && min) {
      console.log(max, min);
      const total = max - min;
      publisher.get('total').setValue(total);
    }
  }

If I execute this, when I update the first field (max) it checks the value, and as min does not exist yet, nothing happens. Correct. Then when I edit the second value (min), this updateTotals is executed a zillion times, total is calculated at the end and updated in the field, but then if I try to edit those fields again and update the values nothing happens.

Any idea why this is happening?

Thanks.

Upvotes: 0

Views: 370

Answers (1)

yurzui
yurzui

Reputation: 214067

When you call setValue valueChange event is fired within updateValueAndValidity. One option should help you

publisher.get('total').setValue(total, { emitEvent: false });

this way your valueChange handler won't be executed infinitely.

Fixed Plunker

Upvotes: 1

Related Questions