Reputation: 341
I'm trying to make service to show spinner progress while loading but I've got error in the console
here the service:
@Injectable({
providedIn: 'root'
})
export class LoadingLockDataService {
public message: string;
public loaderType: string;
public value: number;
public sizeType = 'fullPage';
private overlayRef: OverlayRef = null;
constructor(public overlay: Overlay) {}
public setMessage(message: string): void {
this.message = message;
}
public showOverlay(component: any) {
if (!this.overlayRef) {
this.overlayRef = this.overlay.create();
}
const userProfilePortal = new ComponentPortal(component);
this.overlayRef.attach(userProfilePortal);
}
public hideOverlay() {
if (!!this.overlayRef) {
this.overlayRef.detach();
}
}
}
the component I'm trying to rending dynamically in the overlay:
<div class="spinner-wrapper" [ngClass]="{ fullPage: loadingLockDataService.sizeType === 'fullPage' }">
<div id="center-wrapper">
<div class="mat-spinner-wrapper">
<mat-progress-spinner class="spinner" strokeWidth="2" mode="indeterminate"> </mat-progress-spinner>
</div>
<label class="mat-body label-accent">
{{ loadingLockDataService.message }}
</label>
</div>
</div>
export class LoadingLockComponent implements OnInit {
constructor(public loadingLockDataService: LoadingLockDataService) {}
ngOnInit() {}
}
where I'm calling the service:
ngOnInit() {
// setTimeout(() => {
this.loadingLockDataService.setMessage('Chargement en cours...');
this.loadingLockDataService.showOverlay(LoadingLockComponent);
// }, 1);
this.someService.subscribe(response => {
// do something
this.loadingLockDataService.hideOverlay();
});
}
I've got the following error: "Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'fullPage: undefined'. Current value: 'fullPage: true'. It seems like the view has been created after its parent and its children have been dirty checked. Has it been created in a change detection hook ?"
And I know with setTimeout in where I'm calling the service, it's working but I want to do this properly. I feel that it's because I'm rendering badly the dynamic component.
Upvotes: 0
Views: 924
Reputation: 1884
It's good that you've caught this now - because this is a developer only error. i.e. when you push this application to production, you'll find you'll stop getting this error, even if you changed nothing.
The problem here, lies in when you're calling you're service.
What's essentially happening here, is that your Angular application is asking :
"What's my status of loading?"
"Loading is true."
"Okay great, you're sure?"
"Yep."
"So I'll render that?"
"Yep."
"Okay so is what's rendered (i.e. the loaded status) the same status as the loaded status?"
"No."
"Why?"
"Because the answer changed between when you asked me and when I showed the answer."
"So we aren't loading?"
"No. Not anymore."
That's why it works when you just add a setTimeout
- but you correctly identified, this is not the correct solution for this.
You can fix this correctly, by setting the loading status locally and then either by calling for the answer sooner, before the DOM component is rendered, or after it's all been rendered, or you can ask the ChangeDetectorRef
to be alerted to new updates and make changes accordingly.
i.e. Update your code to the following:
export class LoadingLockComponent implements OnInit {
constructor(public loadingLockDataService: LoadingLockDataService) {
this.loadingLockDataService.setMessage('Chargement en cours...');
this.loadingLockDataService.showOverlay(LoadingLockComponent);
this.someService.subscribe(response => {
// do something
this.loadingLockDataService.hideOverlay();
});
}
You can equally update your code instead, to implement the code, afterViewInit
.
You can look up the ChangeDetectorRef also, for other ways of alerting your Angular Application of a change, outwith its normal checks.
https://angular.io/api/core/ChangeDetectorRef
Upvotes: 1