Stackblitz - https://stackblitz.com/edit/angular-plp4rb-formarray-total-prs9ay
I'm new to RxJS observables.
I've created a form array where the total for a line is quantity * rate. Via valueChanges for the line form group I set the total via the calcTotal method.
On form changes I emit all the lines up to parent to calculate the total.
Questions:
- Do I have any memory leaks?
- Why is it if I stick
debounceTime(1)inside the lineItem valueChanges then this stops working where the calculation is out by the last change?
lineItem.valueChanges.pipe(
takeUntil(this.destroyed$),
debounceTime(1)
).subscribe(value => this.calcTotal(lineItem))
- Why is it if I remove the
{emitEvent: false}and put in adebounceTimeas above the total stops working altogether? - Should i be using some other way like
combineLatest? If so how do I collect the valueChanges observables (I'll figure it out from here if this is required)?
import { Component, OnInit, Input, Output, EventEmitter, ViewChild } from '@angular/core';
import { FormArray, FormBuilder, FormControl, FormGroup } from '@angular/forms'
import { Subject } from 'rxjs'
import { takeUntil, debounceTime} from 'rxjs/operators'
import { MatTable } from '@angular/material';
import { Line } from '../app.component';
@Component({
selector: 'app-total-calculator',
templateUrl: './total-calculator.component.html',
styleUrls: ['./total-calculator.component.css']
})
export class TotalCalculatorComponent implements OnInit {
displayedColumns = ['quantity', 'rate', 'total'];
formGroup: FormGroup;
@Input() lines: Line[];
@Output() linesChange = new EventEmitter<Line[]>();
@ViewChild(MatTable) private matTable: MatTable<any>;
get linesArray(): FormArray {
return this.formGroup.get('lines') as FormArray;
}
private destroyed$ = new Subject<void>();
constructor(private fb: FormBuilder) {
this.buildForm();
}
ngOnDestroy() {
this.destroyed$.next();
this.destroyed$.complete();
}
addLineClick() {
this.addLineFormGroup();
}
addLineFormGroup() {
this.linesArray.push(this
.getLineFormGroup());
this.matTable.renderRows();
}
private buildForm() {
// formarray
this.formGroup = this.fb.group({
lines: this.fb.array([])
});
// subscribe to any changes and emit these
this.formGroup.valueChanges.pipe(
takeUntil(this.destroyed$),
debounceTime(300)
).subscribe(value => {
if (!this.formGroup.valid) {
return;
}
this.linesChange.emit(value['lines']);
});
}
getLineFormGroup(): FormGroup {
let lineItem = this.fb.group({
quantity: new FormControl(),
rate: new FormControl(),
total: new FormControl()
});
lineItem.valueChanges.pipe(
takeUntil(this.destroyed$),
).subscribe(value => this.calcTotal(lineItem))
return lineItem
}
calcTotal(line: FormGroup) {
const quantity = +line.controls['quantity'].value;
const rate = +line.controls['rate'].value;
line.controls['total'].setValue((quantity * rate).toFixed(2), {emitEvent: false});
}
ngOnInit() {
}
}
```