Utilizing a function in an infinite loop within *ngFor along with an asynchronous pipe for an HTTP call

Using a function in an *ngFor statement:

@Component({
  selector: 'foo-view',
  template: '<div *ngFor="let foo of loadAll() | async"></div>'
})
export class FooComponent {

  loadAll(): Observable<Foo[]> {
    return this.http.get(`api/foos`)
      .map(response => response.json() as Foo[]);
  }

}

Upon running the code, it continuously sends HTTP requests in an infinite loop. Why is this happening and how can I prevent it?

P.S. I am aware of the standard workaround like

@Component({
  selector: 'foo-view',
  template: '<div *ngFor="let foo of foos"></div>'
})
export class FooComponent implements OnInit {

  foos: Foo[] = [];

  ngOnInit() {
    this.loadAll().subscribe(foos => this.foos = foos);
  }

  loadAll(): Observable<Foo[]> {
    return this.http.get(`api/foos`)
      .map(response => response.json() as Foo[]);
  }

}

However, I am searching for a way to eliminate the extra variable.

Answer №1

To clarify, the situation is not an endless loop. Angular runs the change detector to determine if any bindings have been updated, triggering the loadAll() method and making an HTTP call. This process is necessary because Angular cannot assume that nothing has changed since the last check. Obviously, this constant rechecking is undesirable. The frequency of these checks may also be influenced by other components, such as its parent.

A solution to prevent this issue is creating a property like foos: Foo[], as demonstrated in your example.

If you prefer not to introduce another state variable, you could establish an Observable chain that replays cached data:

private cached;

ngOnInit() { 
  this.cached = this.http.get(`api/foos`)
    .map(response => response.json() as Foo[])
    .publishReplay(1)
    .refCount()
    .take(1);
}

In your template, you can then simply use:

<div *ngFor="let foo of cached | async"></div>

With this implementation, only one initial request will be made, and subsequent subscribers will receive the cached value without additional requests.

Furthermore, with RxJS 5.4.0 or later versions, you can utilize shareReplay(1) as a more convenient alternative to .publishReplay(1).refCount().

Additionally, you have the option to adjust the Change Detection Strategy of the component using the changeDetection property to manually trigger the change detection process. Refer to ChangeDetectionStrategy for more information.

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

"Once the queryParams have been updated, the ActivatedRoute.queryParams event is triggered once

Within my Angular component, I am making an API call by passing a hash string extracted from the current query parameters. Upon receiving the API result, a new hash is also obtained and set as the new hash query parameter. Subsequently, the next API call w ...

Error in typography - createStyles - 'Style<Theme, StyleProps, "root"

I'm encountering an error in a small React app. Here is a screenshot of the issue: The project uses "@material-ui/core": "4.11.3". In the codebase, there is a component named Text.tsx with its corresponding styles defined in Text.styles.tsx. The styl ...

Guide to passing return value to CanDeactivate Guard post closing the mat-dialog in Angular Material Dialog

I have implemented a CanDeactivate Guard to detect unsaved changes in a form. When changes are detected, a confirmation dialog is displayed before allowing the user to leave the page. The Boolean value returned depends on the action taken in the dialog. C ...

What is the method for specifying a null value in Typescript?

I'm curious if this code snippet is accurate, or if there's a better way to define it. Is there an alternative to using error!? I'm unsure of its meaning and would appreciate clarification. ...

Angular service providing components (TypeScript error)

This is my first time trying to dynamically inject components and so far, I've been successful. However, there's an error in Typescript that's bothering me (I don't like having errors in my code). If you want to check out the app, here ...

Deleting an element from an object in TypeScript

Is there a way in TypeScript to exclude certain elements (e.g. 'id') from an object that contains them? ...

Angular universal issue: 404 error code failing to function properly

After numerous attempts, I find myself at a dead end. Our Angular 11 website requires Universal for SEO purposes, and we have set up a 404 page to redirect when necessary. The issue arises when the redirect returns a status code of 200 instead of 404. To ...

What is the reason for the lack of compatibility between the TypeScript compilerOptions settings 'noEmitOnError: true' and 'isolatedModules: false'?

Whenever I try to execute TypeScript with isolatedModules set as true and then false, I keep encountering this error message: tsconfig.json(5,9): error TS5053: Option 'noEmitOnError' cannot be specified with option 'isolatedModules'. ...

Preventing data loss in an Ionic array - encountering issues with using this.array.push

When attempting to use the storage get method to fill the array storedArr = [], I encounter the error message .push is not a function: storedArr = this.storage.get('stored') ? this.storage.get('stored').then((e) => {e}) : []; The c ...

Having difficulty understanding Symbol.iterator and the return value type in a for-of loop while using TypeScript

Currently, I am delving into type script and embarking on a journey to learn how to craft generic containers for educational purposes. I have developed a LinkedList class with the intention of incorporating the ability to iterate over it, like so: for (co ...

Angular CLI produced the Git command

After starting a project with the Angular CLI, I know it should create a git for me. I typed the following commands in my project directory: git add . git commit -m "some message" Now I want to push. Where do I push this to? Or where is the GitHub r ...

The element is implicitly assigned to an 'any' type due to the inability to use a 'string' type expression to index the 'Breakpoints' type

I have a question related to TypeScript that I need help with. My objective is to create a custom hook for handling media queries more efficiently. Instead of using useMediaQuery(theme.breakpoints.down('md');, I want to simplify it to: useBreakP ...

Accessing node_modules in TypeScript within an Asp.Net Core application

As I work on building a straightforward ASP.NET Core application utilizing npm and TypeScript, the structure of my project is organized as follows: / root | wwwroot | js | AutoGenerated // <-- TS output goes here | view | i ...

What is the best way to outline the specifications for a component?

I am currently working on a TypeScript component. component @customElement("my-component") export class MyComponent extends LitElement { @property({type: String}) myProperty = "" render() { return html`<p>my-component& ...

What happens when a typed Array in Typescript has an undefined property?

I've encountered an issue with a seemingly simple problem that's causing me quite the headache. The code snippet in question is provided below: interface IFoo{ ReturnFirstBarObject1(): string; FillBarArray(array: Array<Bar>): void; } ...

Incorporate a 'Select All' functionality into ion-select by adding a dedicated button

Looking for a way to set custom buttons on ion-select through interfaceOptions in ionic 4? HTML <ion-item> <ion-label>Lines</ion-label> <ion-select multiple="true" [(ngModel)]="SelectedLines" [interfaceOptions]="customAlertOption ...

"Encountering a 404 Not Found error while attempting to access Angular

Welcome to my index.html file! <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>Discover AngularJS2</title> <!-- bootstrap --> ...

The error being thrown at line 538 in the module.js file is causing issues when using

I encountered an error in my Angular 4 project that says "module.js:538 throw err;". Can anyone provide insight on what this means? module.js:538 throw err; ^ Error: Cannot find module 'swagger-js-codegen' at Function.Module._resolveFilena ...

Discovering the root cause of an Angular binding failure

In my Angular application, I have implemented support for multiple browser tabs using angular-redux @select and {{ property }} bindings. Everything was working fine until I decided to configure my angular store with the redux-state-sync middleware to use b ...

The latest version of Angular, Angular 16, brings along its own set of challenges

Just completed the update to version 16 of Angular and encountered the following error message: The injectable CustomMsalInterceptor inherits its constructor from MsalInterceptor, but MsalInterceptor does not have its own Angular decorator. This will resu ...