Home > Software engineering >  How to prevent an infinite loop call while assigning element a value to a service in Angular?
How to prevent an infinite loop call while assigning element a value to a service in Angular?

Time:06-25

I have encountered a problem assigning an element's value to a service. In this scenario, the value of the component is populated with the result of the response from the server. But this calling service falls in a loop and the site ultimately crashes.

This is my component.cs code:

count = -1;

constructor(
    private formBuilder: FormBuilder,
    private referralService: ReferralService
) { }
 
getCount() {
    this.referralService
        .getAll()
        .pipe(first())
        .subscribe((response) => {
            this.count = response.data;
        });
            
    return this.count;
}

And this is my component.html:

<div  role="alert" style="width: 100%">
    <div  style="display: flex">
        You have
        <div style="padding-left: 5px; padding-right: 5px">{{getCount()}}</div>
        counts right now
    </div>
</div>

Because of unknown reasons this getCount() is called countless times.

CodePudding user response:

The goal of Angular change detection is to figure out which parts of the UI need to be re-rendered when changes occur.

To determine whether <div> needs to be re-rendered, Angular needs to execute the getCount() expression to check if its return value has changed.

Because Angular cannot predict whether the return value of getCount() has changed, it needs to execute the function every time change detection runs.

So if change detection runs 300 times, the function is called 300 times, even if its return value never changes.

Depending on the logic inside the function, running a function hundreds of times can become a serious performance issue.

Follow advice from https://stackoverflow.com/a/72751298/15439733 to remedy this.

CodePudding user response:

Subscribe Once

In this line:

<div style="padding-left: 5px; padding-right: 5px">{{getCount()}}</div>

You keep subscribing to some service.

Try this instead:

<div style="padding-left: 5px; padding-right: 5px">{{ count }}</div>

You should call getCount() just once. It doesn't need a return value. And you might also want to unsubscribe:

sub: Subscription;

ngOnInit() {
    this.sub = this.referralService
        .getAll()
        .pipe(first())
        .subscribe((response) => {
            this.count = response.data;
        });
}

ngOnDestroy() {
    this.sub.unsubscribe()
}

There are other ways to unsubscribe, but that would be outside the scope of this question.

Async Pipe

Or you prevent having to subscribe by using the async pipe.

That would look something like this in your script:

count$ = this.referralService
        .getAll()
        .pipe(first());

And in your template:

<div style="padding-left: 5px; padding-right: 5px">{{ count$ | async }}</div>
  • Related