Home > Back-end >  Angular - How to not use ngModel in FormArray
Angular - How to not use ngModel in FormArray

Time:07-18

How not to use ngmodel for the FormArray? I'm trying to add my input fields but I'm using ngModel. Once you add row the value is passed to the next row.

.TS

this.form = this.formBuilder.group({
      id : [0],
      Status: ['', Validators.required],
      array: this.formBuilder.array([this.createList()])
    })

createList(): FormGroup {
    return this.formBuilder.group({
      id: [0],
      QtyOrder : ['0', Validators.required],
      QtyDelivered : [''],
      QtyRejected : ['', Validators.required],
      QtyReceived : ['', Validators.required],
    })
  }

get array():FormArray{
return this.form.get('array') as FormArray;
}

Calculate(){
 let total = this.form.get('array') as FormArray;
 return total.controls.map((x) => x.get('QtyDelivered').value - x.get('QtyRejected').value).reduce((sum,amount) => sum   amount, 0);
}

.HTML ----Here I want to put the total.---

<input type="text" formControlName="QtyReceived" [ngModel]="Calculate()">

CodePudding user response:

You can add events for when the QtyDelivered and QtyRejected controls are key in with value, it will trigger the Calculate() method.

<input formControlName="QtyDelivered" (input)="Calculate()" />

<input formControlName="QtyRejected" (input)="Calculate()" />

And modify the Calculate method to bind the calculated value to QtyReceived control.

Calculate() {
  let total = this.form.get('array') as FormArray;

  total.controls[0]
    .get('QtyReceived')
    .patchValue(
      total.controls
        .map((x) => x.get('QtyDelivered').value - x.get('QtyRejected').value)
        .reduce((sum, amount) => sum   amount, 0)
    );
}

Sample StackBlitz Demo

Note that you are performing the calculation for all FormGroup in FormArray, it is fine when you have only one FormGroup in FormArray, but if you are trying to perform the calculation for each row (when there is more than one FormGroup in FormArray), the calculation is incorrect.


In case you are performing the calculation by row, you need to specify the FormGroup to be used for calculation.

Solution 1: Trigger with (input) event.

<input formControlName="QtyDelivered" (input)="Calculate(i)" />

<input formControlName="QtyRejected" (input)="Calculate(i)" />
Calculate(i) {
  let total = this.form.get('array') as FormArray;
  let formGroup = total.controls[i] as FormGroup;

  formGroup
    .get('QtyReceived')
    .patchValue(
      formGroup.get('QtyDelivered').value - formGroup.get('QtyRejected').value
    );
}

Sample StackBlitz Demo (Solution 1)


Solution 2: Subscribe FormControl valueChanges event.

this.array.controls.forEach((g: FormGroup) => {
  g.get('QtyDelivered')
    .valueChanges.pipe(debounceTime(500))
    .subscribe((x) => {
      g.get('QtyReceived').patchValue(this.Calculate(g));
    });

  g.get('QtyRejected')
    .valueChanges.pipe(debounceTime(500))
    .subscribe((x) => {
      g.get('QtyReceived').patchValue(this.Calculate(g));
    });
});
Calculate(formGroup: FormGroup) {
  return (
    formGroup.get('QtyDelivered').value - formGroup.get('QtyRejected').value
  );
}

Sample StackBlitz Demo (Solution 2)

Make sure that you have to unsubscribe the observable for valueChanges when the component is destroyed for better optimization.

  • Related