Home > Mobile >  Angular ngFor running in infinite loop when displaying array
Angular ngFor running in infinite loop when displaying array

Time:11-09

i'm currently trying to make a Logbox for my webapp. It gets an Array of logs and should display them row by row in a div. Im using ngFor and looping trough my Array of logs and then displaying them.

My problem is now that the logs get displayed infinite times, not just 5 times (5 Array entries in list) like it should.

Does somebody have a hint what im missing?

logs.component.html

<div >
    <div >
      <div  *ngFor="let log of this.logService.getLogs()">
        <app-singlelog [when]="log.when" [type]="log.type" [data]="log.data"></app-singlelog>
      </div>
    </div>
  </div>

log.service.ts

export class LogService {
  private logArray = [];
  /* private logObject = {} as Log; */

  constructor(private httpservice: HttpserviceService) { 
    
  }

  public getLogs(): Array<Log> {
    this.httpservice.getLogs().subscribe(data => {
      data.forEach(index => {
        let logObject = {} as Log;
        logObject.when = index.when;
        logObject.type = index.type;
        logObject.data = index.data;
        this.logArray.push(logObject);
      })
    }
    )
    return this.logArray;
  }
}

Thanks :)

CodePudding user response:

Don't use function calls from html template to display data.
Instead, call the getLogs() function from the Angular ngOnInit() function, and store the response in a variable. Then loop on that variable:

export class LogService implements OnInit {
// ...

logs = [];

ngOnInit() {
   this.getLogs();
}

getLogs(): Array<Log> {
    this.httpservice.getLogs().subscribe(data => {
      data.forEach(index => {
        let logObject = {} as Log;
        logObject.when = index.when;
        logObject.type = index.type;
        logObject.data = index.data;
        this.logArray.push(logObject);
      });
      // assign the variable here:
      this.logs = data;

    });
}

In the template:

 <div  *ngFor="let log of logs">
   <app-singlelog [when]="log.when" [type]="log.type" [data]="log.data"></app-singlelog>
</div>

The reason behind this is the fact that Angular calls your getLogs function on every page rendering cycle. But you should call the http request only once, when initalising the component.

Don't forget to unsubscribe from your Observable. ;) - corrected from the comment below.

CodePudding user response:

You can also use the reactive approach and do the following:

Define the observable once in your component:

logs$ = this.httpservice
    .getLogs()
    .pipe(
      shareReplay(),
      map((data) => data.map(({ when, type, data }) => ({ when, type, data })))
    );

Include in your component HTML the following:

<div  *ngFor="let log of logs$ | async">
   <app-singlelog [when]="log.when" [type]="log.type" [data]="log.data"></app-singlelog>
</div>
  • Related