What strategies can we implement using Angular's change detection mechanism to enhance performance?

I'm embarking on my maiden voyage into the world of open source projects with a school gradebook. Despite being new to Angular, I'm facing a challenge regarding the runtime performance of the application. The generation of form controls dynamically based on students and assignments is proving to be time-consuming in terms of rendering.

Although I attempted to detach the change detector, it still lags behind when triggered during change detection.

A deep dive into Chrome Dev Tools reveals that a significant chunk of time is consumed in the process of change detection.

  private createFormControls( ) {

    const gradeGroup = this.gradeControls;
    this.clearAllGradeControls(gradeGroup);

      for (let i = 0; i < this.gradebook.students.length; i++) {
        const student = this.gradebook.students[i];
        const studentGrades = this.gradebook.grades.filter( g => g.userId == student.userId);

        for (let j = 0; j < this.gradebook.assignments.length; j++) {
          const assignment = this.gradebook.assignments[j];
          const key = this.createKey(student.userId, assignment.id);
          const grade = studentGrades.find( g => g.assignmentId == assignment.id );
          let fg = new FormGroup({
              grade: new FormControl(grade ?  grade.grade : ''),
              userId: new FormControl(student.userId),
              assignmentId: new FormControl(assignment.id),
           });
            gradeGroup.addControl(key,  fg);
        }      
      }   

  }

Stackblitz https://stackblitz.com/github/omarolivo/Gradebook

Github: https://github.com/omarolivo/Gradebook

How can I optimize the performance while dynamically generating rows and columns of form controls?

UPDATE

Upon identifying the root cause of the performance issue, it seems that change detection plays a major role in slowing down the component. I've experimented with converting the data array into an RxJS observable, yet the struggle persists with change detection.

Any recommendations on the most efficient pattern/architecture to leverage change detection?

Answer №1

Upon further investigation, it became clear that the issue was not actually caused by ChangeDetection as initially suspected. What you are observing is a false positive. The true bottleneck lies in the assignment/rendering process of the hefty FormGroup to the <form> element (which coincidentally occurs during change detection when the value gets updated).

Initially, I considered recommending the use of Angular's Resolve Guards to "bypass" some of the change detection processes involved in modifying the FormGroup, but upon testing, I discovered that the root of the problem was elsewhere. However, I still suggest implementing this for architectural reasons rather than performance ones. My suggestion would be to centralize all logic within a service and have the guard utilize that service to initiate a resolve call.

The primary concern here is the sheer number of FormGroups present in your form. With 25 individuals across 39 columns, you're dealing with a total of 975 FormGroups. Each of these groups contains 3

FormControls</code, totaling almost 3000 controls in total. This size is significantly large, and there may not be standard solutions readily available.</p>

<p>To address this issue, consider reducing the number of visible fields displayed at once. Segmenting your <code>*ngFor
elements into smaller subsets and conditionally rendering them using *ngIf based on factors like scroll position can help manage the overwhelming display of fields.

You could also explore more advanced lazy loading techniques for *ngFor elements. There is an intriguing article detailing the creation of a 'lazy' *ngFor directive which might be worth experimenting with.

Additionally, adopting OnPush change detection mode is advised as it can provide a marginal boost in performance under such circumstances.

If any additional insights come to mind, I'll revisit and update this post accordingly.

Best of luck!

EDIT:

The Angular CDK offers support for Virtual Scrolling functionality. By utilizing the

<cdk-virtual-scroll-viewport>
tag to create a scrollable container and replacing *ngFor directives with *cdkVirtualFor, you can leverage this feature. According to the documentation:

The

<cdk-virtual-scroll-viewport>
efficiently displays large lists by only rendering items that are currently visible on-screen. Rather than loading hundreds of elements at once, virtual scrolling simulates rendering all items by adjusting the height of the container to match the total number of elements to be rendered and displaying only those within view.

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

Utilizing Typescript with Vue 3's Injection Feature

Using the new Vue 3 Composition API, I have created a "store" for reactive data. const state = reactive<State>({ accessToken: undefined, user: undefined, }); export default { state: readonly(state), } When my app is created, I pass the store ...

Developing a TypeScript NodeJS module

I've been working on creating a Node module using TypeScript, and here is my progress so far: MysqlMapper.ts export class MysqlMapper{ private _config: Mysql.IConnectionConfig; private openConnection(): Mysql.IConnection{ ... } ...

Processing of hierarchical JSON structure

I have a JSON array that I am trying to duplicate only once while keeping it unique. Here is the code I have attempted: return_data = {}; return_data.planner = [{ "date": "2019-08-30T12:10:08.000Z", "event": [{ "name": "Event 1", "col ...

Issue with ADFS 2016 oAuth: Users not being redirected to login page post logout

Having an issue with ADFS 2016 and my Angular application using ng2-adal js for authentication and authorization. After users logout, they are not redirected back to the login page. Debug traces in Event Viewer show the following error: Error: OAuthSignou ...

Navigational highlight effect in Angular routing

I'm currently working on implementing the Scrollspy effect into my Angular project. I want to ensure that when a user clicks on a link, instead of being directed to a new page, the current component smoothly scrolls up and transitions to the next comp ...

Angular-cli is throwing an error stating it cannot locate the module '@ngtools/json-schema'

After running npm update in my project, I seem to be encountering an issue whenever I try to run ng serve. Error: Cannot find module '@ngtools/json-schema' Oddly enough, the @ngtools file is clearly present in my node_modules directory. I&apo ...

Accessing the various types within a monorepo from a sibling directory located below the root folder

Seeking assistance in resolving a referencing types issue within a TypeScript monorepo project. Unsure if it is feasible given the current setup. The project structure is as follows: . ├── tsconfig.json ├── lib/ │ └── workers/ │ ...

The error TS2304 occurs when the e2e tsconfig types cannot find the name 'browser'

I am facing challenges while setting up a sample angular project with a basic webdriverio end-to-end test, encountering some compilation errors in my e2e test. Setting up tsconfig The project is configured with the following key files: e2e / test / [e2e t ...

Identifying shifts in offsetTop

In my design, I have a page where scroll bars are not allowed, meaning all content must be visible at once. The image below shows the basic layout of the screen to give you an idea. The layout consists of two blocks - Block 1 and Block 2. Block 1 is expan ...

Error encountered in ngOnInit when unit testing services: 'map is not a function'

While attempting to test a component using Jasmine & Karma, I encountered an unfamiliar error. Specifically, when trying to determine if my services have been called in ngOnInit(), I received the following error message: Failed: Uncaught (in promise): ...

Retrieving document attributes from a Mongoose Model with the help of Typescript

Incorporating Typescript with Mongoose, my aim is to retrieve properties from a Model. Taking the illustrated UserModel as an example import mongoose, { Schema } from 'mongoose'; const userSchema: Schema = new mongoose.Schema({ _id: mongoos ...

Running Protractor e2e tests with various Angular environment variables is a great way to test your application in

I utilize Angular environment variables to easily set up API endpoints. You can find these configurations in the following environment files: .\src\environments: environment.ts environment.test.ts environment.prod.ts These environme ...

When Ionic slides are set to loop continuously from the first slide to the last, the pager does not update accordingly

While utilizing Ionic slides with pager and loop set to true, I encountered an issue where swiping left from the first slide would open the last slide, but the pager dots were not updated and the view wasn't bound to the model. It would only work corr ...

Preventing OnBlur from triggering in a password management system

Managing my passwords with 1Password and using its Chrome extension has been really convenient for me. However, I recently discovered a problem on my website where the OnBlur event does not trigger when I tab out of any input field. Surprisingly, the event ...

Determine in React whether a JSX Element is a descendant of a specific class

I am currently working with TypeScript and need to determine if a JSX.Element instance is a subclass of another React component. For instance, if I have a Vehicle component and a Car component that extends it, then when given a JSX.Element generated from ...

What causes the return value type in a functional interface to be loosely implemented in Typescript?

In an attempt to explain a specific partial type of return value for a functional interface, I have encountered an issue. Within my IStore interface, there is only one property called test. When assigning this interface to the function foo, which returns ...

What is the specific purpose of the 'extend' keyword in Typescript?

Recently, I have been delving into the realm of Javascript/Typescript/React as a PHP developer. During my learning process, I encountered a few perplexing issues that I could not fully grasp. In light of this, I am reaching out to the experienced indiv ...

When passing parameters through a URL in TypeScript, the display shows up as "[object object]" rather than as a string

Hey there! I'm trying to pass some string parameters to my URL to fetch information from an API. Everything seems fine, and when displayed in an alert, the URL looks exactly as it should (no [object, object] issue). var startDate = "2020-09-20"; var ...

The styled component is not reflecting the specified theme

I have a suspicion that the CSS transition from my Theme is not being applied to a styled component wrapped in another function, but I can't pinpoint the exact reason. I obtained the Basic MUI Dashboard theme from this source and here. Initially, inte ...

Angular 16's platform-driven redirection functionality

I'm facing a challenge with my module that has its own subrouting. The page only consists of a header and material tabs linked to my routing, with the need for the landing tab to differ between desktop and mobile. To handle platform detection, I have ...