Improving render speed in Angular 7 FormArray

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.

Answer №1

After spending numerous hours investigating and troubleshooting, I have reached the conclusion that the performance issues stem from a combination of several directives.

Surprisingly, the FormControl itself is not the culprit behind the delay I am encountering. It turns out that calls to the Renderer(2) are causing significant slowdowns. When coupled with other computationally heavy processes, this led to the observed behavior. The unexpected discovery was that something as simple as ".addClass" could consume approximately 400ms in rendering time.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for overlaying a webpage with several Angular components using an element for disabling user interactions

I currently have an asp.net core Angular SPA that is structured with a header menu and footer components always visible while the middle section serves as the main "page" - comprised of another angular component. What I am looking to achieve is ...

Error encountered with react-query and UseQueryResult due to incorrect data type

I'm currently implementing react-query in my TypeScript project: useOrderItemsForCardsInList.ts: import { getToken } from '../../tokens/getToken'; import { basePath } from '../../config/basePath'; import { getTokenAuthHeaders } fr ...

The null error occurs when rendering with React's state array

When I try to call an API that emits JSON, I am encountering an issue. I call the promise API function in componentDidMount, set the state, and then call it in the render method, but it always returns a null error. I need assistance, please. Interface fo ...

Ways to conceal a component based on a specific condition?

In my Angular 8 application, I need to dynamically hide a component based on a specific condition. The condition I want to check is: "status === EcheqSubmissionStatus.EXPIRED" Initially, I attempted the following approach: EcheqProcessComponent templat ...

Executing axios calls within other axios calls and altering state in React before all calls have completed

Currently, I am working on implementing nested axios calls to create the desired object by making multiple API requests. However, I am facing an issue where the state updates before all requests have finished, causing my table to populate entry by entry ...

What is the best method for accessing all the projected elements within a Component?

What is the best approach for accessing all projected elements within a Component? Consider an example where AppComponent projects various links and images into TestComponent: @Component({ selector: 'test', template: '<ng-content> ...

How to activate a textbox in Angular 6 when a checkbox is selected:

Looking for examples related to this topic, all I've come across are AngularJs examples. Is there a way to enable my textbox based on the status of a checkbox in the same row, without directly binding them through a boolean value or using JavaScript? ...

Typescript and MomentJS integration - What is the data type of the moment() function?

Currently in the process of upgrading my project from ES5 to ES6, I've encountered a problem with MomentJS (version 2.18.1). The issue arises when dealing with variables that are Moment objects and the inability to call moment() on them. For instance ...

Modifying the Iterator Signature

My goal is to simplify handling two-dimensional arrays by creating a wrapper on the Array object. Although the code works, I encountered an issue with TypeScript complaining about the iterator signature not matching what Arrays should have. The desired fu ...

Forever waiting: Angular HTTP requests stuck in limbo

Switching from MongoDB to MySQL for my Angular/NodeJS project has brought about some challenges, particularly with handling HTTP Requests. I have tried GET and POST requests, but GET always remains pending and eventually fails, while POST does not successf ...

"Troubleshooting the issue of Angular's ViewContainerRef.createComponent malfunctioning on subsequent

My application is structured into Header, Context, and Content sections. I am looking to dynamically inject different components into the Context Component (viewContainerRef) based on the route and other conditions. To achieve this functionality, I have ...

What is the recommended way to handle data upon retrieval from a Trino database?

My goal is to retrieve data from a Trino database. Upon sending my initial query to the database, I receive a NextURI. Subsequently, in a while loop, I check the NextURI to obtain portions of the data until the Trino connection completes sending the entire ...

CreateAsyncModule using an import statement from a variable

When trying to load a component using defineAsyncComponent, the component name that should be rendered is retrieved from the backend. I have created a function specifically for loading the component. const defineAsyncComponentByName = (componentName: strin ...

Update button Image upon click

Is there a way to swap the image on a button when it's clicked? I want my button to start with one icon, but then change to another icon once it has been clicked. How can I achieve this effect? Any suggestions on how to make this happen? Check out ...

The specified type 'Observable<{}' cannot be assigned to the type 'Observable<HttpEvent<any>>'

After successfully migrating from angular 4 to angular 5, I encountered an error in my interceptor related to token refreshing. The code snippet below showcases how I intercept all requests and handle token refreshing upon receiving a 401 error: import { ...

Android 403 error encountered when trying to access the Google Sign-In client script from the accounts.google.com URL with async defer attributes included

When I run my Angular app (built with the Ionic framework) locally in a browser, everything works fine. However, when I try running it through Android Studio or package and push it to my mobile phone, I encounter a 403 error. The issue seems to be related ...

Blazing Paths with an Isomorphic Application Using Inferno and TypeScript

I am currently working on building an isomorphic application using Express and Inferno. Strangely, I have not come across any similar projects online. In my attempt to create one myself by following a guide on Razzle, specifically related to Inferno, I enc ...

Angular 4 router issue: Outlet has already been activated and cannot be activated again

I recently updated my application from Angular2 to Angular 4. Previously, everything, including routing, was functioning flawlessly. However, since the upgrade, I have encountered issues with routing. Whenever I click on a link, the redirection fails and ...

Dealing with challenges in resolving controllers with AngularJS and TypeScript

Getting an error with this script: https://gist.github.com/whisher/6231714 The error I'm encountering is: Unknown provider: albumsProvider <- albums this.app.config(($routeProvider:ng.RouteProvider) => { $routeProvider. ...

Issue encountered with Syncfusion ej2-angular Pivot Table when using subtraction operator - ERROR SyntaxError: Invalid operand in postfix operation

I encounter issues specifically when utilizing the minus operator calculatedFieldSettings: [ { name: 'Binaural', formula: '"Sum(the_order_count)" == "0" ? "0" : ("Sum(the_unit_count)" - "Sum(the_order_count)") / "Sum(the_order_count)" ...