Currently, I am in the process of developing an angular component that is responsible for rendering and modifying invoices. In order to edit the line items within the invoice, I have implemented a FormGroup containing a FormArray of line item forms:
lineItemForm: FormGroup = this.formBuilder.group({
lineItems: this.formBuilder.array([])
});
Whenever the line items are passed into the component through @Input, a new FormGroup is generated for each individual line item.
set lineItems(lineItems: InvoiceLineItem[]) {
this.lineItemForm.controls['lineItems'] = this.formBuilder.array(
lineItems.map(lineItem => {
return this.createLineItemForm(lineItem);
})
);
this._lineItems = lineItems;
}
private createLineItemForm(lineItem: InvoiceLineItem): FormGroup {
return this.formBuilder.group({
_id: [lineItem._id],
number: [lineItem.number],
amount: [lineItem.amount, Validators.compose([Validators.required, NumberValidator.validateNumber(2)])],
title: [lineItem.title],
netprice: [lineItem.netprice, Validators.compose([Validators.required, PriceValidator.validatePrice()])],
netpriceTotal: [lineItem.netpriceTotal, Validators.compose([Validators.required, PriceValidator.validatePrice()])],
grosspriceTotal: [lineItem.grosspriceTotal],
taxrate: [lineItem.taxrate, Validators.compose([Validators.required, IntegerValidator.validateInteger()])],
taxTotal: [lineItem.taxTotal],
from: [lineItem.from, DateValidator.validateDate('DD.MM.YYYY HH:mm')],
to: [lineItem.to, DateValidator.validateDate('DD.MM.YYYY HH:mm')],
pageIndex: [],
rowOrder: []
});
}
The simplified template code appears as follows:
<div formArrayName="lineItems"
*ngFor="let lineItem of lineItemForm.controls['lineItems'].controls; trackBy:getLineItemIdentity; let i = index; let even = odd">
<div *ngFor="let column of alwaysVisibleColumns; trackBy:getColumnIdentity; let col = index; let f = first; let l = last;"
[formGroupName]="i">
<div [formControlName]="column.field" some-custom-directives...></div>
</div>
</div>
I acknowledge that I am utilizing div elements as formControls (employing custom directives to enable them as content-editable inputs).
Everything works perfectly when there are fewer than 10 line items. However, the UI becomes unresponsive for around 10 seconds (!!!!!!) when there are approximately 30-40 line items present on the invoice - which is highly inconvenient.
I suspect that the issue lies with how the individual form controls are being rendered. When simply displaying plain text without form controls, the rendering speed significantly improves.
Is there any enhancement I can make on my end to address this issue, or is it something that requires action from the Angular team? Or perhaps the current implementation will never be suitable for my scenario, and I need to explore alternative solutions?
Here you can find a link to the performance measurement created using Firefox dev-tools.