Using a function to implement *ngFor results in generating a loop

When using *ngFor in Angular with a function that returns data, the function gets called multiple times and can sometimes result in a loop:

app.component.ts

export class AppComponent {

 getArray(): string[] {

   //I can track when this function is called
   console.log('getArray has been called')

   return ['number one', 'number two']
 }

}

app.component.html

<h1 *ngFor="let item of getArray()">
 {{ item }}
</h1>

My console:

https://i.sstatic.net/MNrI6.png

As a result, the getArray() function is being called multiple times and I am unsure why.

Answer №1

Insight

The reason why Angular is known for being "multiply time" intensive is because it evaluates all expressions in your template during every change detection cycle. This process is initiated by the ApplicationRef.tick method.

Upon application startup, the tick method is immediately executed, following which it is overseen by the ngZone.onMicrotaskEmpty subscription.

In addition, each tick method performs an extra check called checkNoChanges when in dev mode.

Thus, the sequence of events unfolds as follows:

App starts
   loadComponent
      tick
        checkChanges
              evaluate getArray()
        checkNoChanges
              evaluate getArray()
  ngZone.onMicrotaskEmpty
      subscribe(all promises have been executed)
         tick
           checkChanges
              evaluate getArray()
           checkNoChanges
              evaluate getArray()

      ...some time later
      subscribe(you click somewhere)
         tick
           checkChanges
              evaluate getArray()
           checkNoChanges
              evaluate getArray()
      subscribe(you make a http request)
         tick
           checkChanges
              evaluate getArray()
           checkNoChanges
              evaluate getArray()

Prior Suggestion

To optimize performance, it is advisable to refrain from using complex or dynamic calculations within Angular templates that trigger new outputs with each change detection iteration.

Specifically in your case,

<h1 *ngFor="let item of getArray()">

generates a fresh array on every template check. Consequently, the ngForOf directive interprets this modification and attempts to re-render the list (if items are objects).

A more efficient approach involves pre-defining the array before rendering in the code:

arr = ['number one', 'number two']

<h1 *ngFor="let item of arr">

Alternatively, consider implementing a unique key for each item if using trackBy with ngForOf directive.

Further References

Answer №2

@Yurzui's response may not be entirely accurate. Here is an illustration: https://example.com/edit/example-url

The reason it is called multiple times is because of how the Angular lifecycle hooks function. These are the console logging events during page load when all lifecycle hooks are connected:

ngOnInit
ngDoCheck                       
ngAfterContentInit
ngAfterContentChecked           
!>   getArray executed               
ngAfterViewInit
ngAfterViewChecked              
!>   getArray executed               
ngDoCheck                       
ngAfterContentChecked           
!>   getArray executed               
ngAfterViewChecked             
!>   getArray executed            

Upon examining these logs, it becomes evident that they correspond with your screenshot depicting 4 instances of getArray() being invoked.

Answer №3

To perform modifications on your "object", consider utilizing Angular pipes.

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

Leveraging local resources to create images with the help of @vercel/og and Next.js

Utilizing the latest @vercel/og library for generating meta-tag images has been quite intriguing. The official example showcases how to leverage images from an external source. The Quandary at Hand <img src={"https://res.cloudinary.com/iqfareez ...

Establishing a connection between MySQL database and an Ionic/Angular application

I have been working on an Ionic/Angular project and I'm facing difficulties in establishing a connection with my MySQL database (mariadb). Despite trying various solutions from online sources, I keep encountering numerous error messages. Any guidance ...

How to transition from using a CDN to NPM for implementing the Google Maps JavaScript MarkerClusterer?

Currently integrating Google Maps JavaScript MarkerClusterer from CDN, I am considering transitioning to the NPM version for Typescript checking in my JavaScript files. However, I am encountering difficulties understanding how to make this switch. The docu ...

The Angular 5 route guard on a component-less route does not successfully redirect

My current challenge involves setting up a component-less route with a route guard in Angular 5. Here is my code snippet: const routes: Routes = [ {path: '', runGuardsAndResolvers: 'always', canActivateChild:[AppRouteGuard], children: ...

What is the best way to extract all Enum Flags based on a Number in TypeScript?

Given: Enum: {1, 4, 16} Flags: 20 When: I provide the Flags value to a function Then: The output will be an array of flags corresponding to the given Enum: [4, 16] Note: I attempted to manually convert the Enum to an array and treat values as numb ...

Slate - developing a TypeScript function to filter and retrieve an object containing the highest property value

Check out this NEW RELATED QUESTION: I need to extract the largest number from a given object set. I am struggling with finding a solution. I have tried using max but I think my skills are lacking. Here is the code I have so far: @Function() pub ...

Retrieving the chosen option using a change event listener

Is there a way to retrieve the selected option using a change listener in TypeScript? I have come across JavaScript examples where the value is retrieved through event., but I am unable to locate any field that contains the selected option. <!DOCTYPE ...

Pass a delay to an Angular 2 component animation by defining it as an input parameter

Is it possible to set the delay of a component's animation directly from the HTML code? For example: HTML: <circles[delay]="'10000ms'"></circles> Typescript (ts): @Component({ selector: 'circles', templateUrl: ...

What is a way to construct an object without resorting to casts or manually declaring variables for each field?

Click here for a hands-on example. Take a look at the code snippet below: export type BigType = { foo: number; bar?: number; baz: number; qux?: string[]; }; function BuildBigType(params: string[]) { // Here's what I'd like to do: ...

Combining an array of objects in Angular 2 based on the object's name

When I receive a response from the backend, it looks like this: [ { "id": 1, "restaurant_name": "Ajisen Ramen Toronto", "description": "Japanese Restaurant", "phone": "416-977-8080", "address": { "id": 3, ...

Typedoc Error: Attempted to assign a value to an undefined option (mode)

After installing typedoc with the command npm install typedoc --save-dev, I proceeded to add typedocOptions to tsconfig.json: { "compileOnSave": false, "compilerOptions": { "baseUrl": "./", // ...some lin ...

The ngAfterViewChecked function seems to be caught in an endless loop

I am facing an issue where the <cdk-virtual-scroll-viewport> starts from the bottom, but I am unable to scroll up. I suspect that this problem is related to the use of AfterViewChecked. Even after trying AfterViewInit, the issue persists. @ViewChil ...

Unable to find a matching router for the Angular component

In my project, I am tasked with creating a specific path structure: "myapp/category/subcategory". The "myapp/" part is fixed, while the category is represented by the variable "cat.title" and subcategory by "sub.title". To achieve this, I have JSON data ...

Exploring the implementation of the jquery .counterUp function within Angular 5

I am working on implementing a counter up view for my company's website using the jQuery counterUp function. Despite adding script tags for it, Angular is not recognizing the function. if(st >= hT ){ $('.counter').counterUp({ dela ...

Sync user information when alterations are made on a different device

As I create a Discord clone using Next.js, I've encountered an issue where when a server is deleted, another client can still see and use the server until the page is reloaded. When testing out the official Discord web app, changes seemed to happen in ...

Angular dynamic data internationalization

Incorporating internationalization [i18n] into my angular project has been successful for static content, but I am encountering challenges with dynamic content. Below is a snippet of my code: Static: <div>{{ 'ADD ENTRY' | translate }} &l ...

Sometimes, Express may return the message "not found" on and off

After working with express for many years, I find myself a bit out of practice with TypeScript - and it seems like my eyesight is failing me! This is the first time I've encountered this issue, so I must be missing something... My current dilemma is ...

What causes the function endpoint to become unreachable when a throw is used?

One practical application of the never type in typescript occurs when a function has an endpoint that is never reached. However, I'm unsure why the throw statement specifically results in this unreachable endpoint. function error(message: string): ne ...

"Enhance your user experience with an Angular material list featuring the ability

I am looking to enhance an angular selection list by allowing users to add new items without losing their current selections. My usual approach involves adding a method in the component to update the data list and then recreating the MatSelectionList bound ...

Issue with Angular 5 - Deselect all checkboxes not reflecting in the UI

I am currently working on integrating a reset button into a Reactive form in Angular 5. The reset functionality works flawlessly for all form fields, except for the dynamically created multiple checkboxes. Although it seems like the reset operation is hap ...