Paco Zevallos
Paco Zevallos

Reputation: 2275

valueChanges in Array reactive forms

I have a reactive form that contains an Array of objects with 2 fields. I am trying to do a simple multiplication between those two fields whose result will be stored in a third field. I subscribed with valueChanges to the changes of the Array and it works, but the values of the form does not listen to those changes.

Here's an example in Stackblitz: https://stackblitz.com/edit/angular-ivy-qr2bg3?file=src/app/app.component.ts

enter image description here

What is the correct way to subscribe to changes in an Array containing objects?

formDoyle: FormGroup;
  largo: number;
  resultPiesTablares = 0;

  constructor( private fb: FormBuilder ) { }

  ngOnInit(): void {

    this.formDoyle = this.fb.group({
      calculos: this.fb.array([
        this.getCalculo()
      ])
    });

    this.formDoyle.get('calculos')?.valueChanges.subscribe(res => {
      const control = <FormArray>this.formDoyle.controls['calculos'];
      this.resultPiesTablares = 0;
      for (let i in res) {
        let diametroMenor = res[i].diametroMenor;
        let largo = res[i].largo;
        let resultPiesTablares = diametroMenor * largo;
        control.at(+i).get('subTotal')?.setValue(resultPiesTablares, { onlySelf: true });
      }
    });
    
  }

  private getCalculo() {
    const numberPatern = '^[0-9.,]+$';
    return this.fb.group({
      diametroMenor: ['', [Validators.required, Validators.pattern(numberPatern)]],
      largo: ['', [Validators.required, Validators.pattern(numberPatern)]],
      subTotal: ['']
    });
  }

  agregarCalculo() {
    const control = <FormArray>this.formDoyle.controls['calculos'];
    control.push(this.getCalculo());
  }

   removeCalculo(i: number) {
    const control = <FormArray>this.formDoyle.controls['calculos'];
    control.removeAt(i);
  }

Upvotes: 0

Views: 3307

Answers (2)

Paco Zevallos
Paco Zevallos

Reputation: 2275

In the end what worked for me was to subscribe to the changes of each value:

See updated stackblitz: https://stackblitz.com/edit/angular-ivy-qr2bg3?file=src/app/app.component.ts

for (let i in calculos) {
    control.at(+i).get('diametroMenor')?.valueChanges.subscribe( res => {
      let resultPiesTablares = res * calculos[i].largo;
      control.at(+i).get('subTotal')?.setValue(resultPiesTablares, { onlySelf: true });
    });

    control.at(+i).get('largo')?.valueChanges.subscribe( res => {
      let resultPiesTablares = calculos[i].diametroMenor * res;
      control.at(+i).get('subTotal')?.setValue(resultPiesTablares, { onlySelf: true });
    });
  }

Upvotes: 1

Rachid O
Rachid O

Reputation: 14002

You are not getting the new value of subTotal in your valueChanges listener because you put { onlySelf: true } which is a good thing because otherwise you would get an infinite loop.

If you want to listen to the subTotal you need to subscribe to it:

control.at(0).get('subTotal').valueChanges.subscribe(res => {

        console.log('subTotal:', res)

});

Upvotes: 0

Related Questions