When using getters inside templates, it seems that Angular's change detection can get stuck in a loop with the getter being called multiple times. Despite researching similar issues, I have not been able to find a clear solution.
Background info:
I personally believe that using getters in templates is the most maintainable approach. However, because Angular cannot determine if the getter value has changed without calling it, it ends up calling it repeatedly. So far, I have identified three possible alternatives:
- Avoid using getters and make all properties public for direct access
- Assign the value of each getter to a public property on the component and bind that instead of the getter in the template
- Change Angular's changeDetection mode from default to onPush
Option 1 goes against the benefits of using TypeScript classes. Option 2 seems like unnecessary code duplication and could reduce maintainability, while option 3 would require significant refactoring.
To illustrate, here is a simplified example:
Model:
export class UserModel {
private id: string;
get getId() {
console.log('Getting id');
return this.id;
}
set setId(id) {
this.id = id;
}
constructor() {
}
}
Component.html
<h1>Test</h1>
<p>{{user.getId}}</p>
Component.ts
import {Component, OnInit} from '@angular/core';
import {UserModel} from './user.model';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
public user: UserModel;
ngOnDestroy() {
if (this.userObserver) { this.userObserver.unsubscribe(); }
}
ngOnInit() {
this.userObserver = this.userObservable.subscribe(
(data: UserModel) => {
this.user = data;
},
(err: any) => {
console.error(err);
});
}
}
This will generate the following console log: console.log output
Does anyone have recommendations for the best practice to avoid these loops when working with complex models in Angular? Or perhaps a proper approach to troubleshooting this issue, as my current method involves logging the getter methods and monitoring memory usage spikes.
EDIT (Answer) After further investigation and analyzing stack traces, I discovered that an infinite change detection loop was actually caused by a service we inject named 'Sentry'. It appears that using console.log triggers change detection issues. There is a related GitHub issue here: github.com/getsentry/sentry-javascript/issues/1883. Although I did not find a solution (as it seems inherently incompatible), I will update if I come across a fix for this issue.