Reputation: 3311
Here is my LoadingScreenService:
import { Inject, Injectable } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations';
import { NavigationStart, NavigationEnd, Router, NavigationCancel } from '@angular/router';
@Injectable()
export class LoadingScreenService {
private loadingScreenEl: HTMLElement = null;
private player: AnimationPlayer;
private isEnabled = false;
private isShowing = false;
private isHiding = false;
constructor(
private animationBuilder: AnimationBuilder,
@Inject(DOCUMENT) private document: any = null,
private router: Router = null
) {
if (document !== null) {
this.loadingScreenEl = this.document.body.querySelector('#fuse-loading-screen');
}
if (router !== null) {
this.router.events.subscribe((event) => {
if (event instanceof NavigationStart) {
setTimeout(() => {
this.show();
}, 0);
}
if (event instanceof NavigationEnd || event instanceof NavigationCancel) {
setTimeout(() => {
this.hide();
}, 0);
}
}
);
}
}
/**
* @param {number} wait Duration (ms) of a timeout before showing the spinner
*/
show(wait: number = 1000) {
if (this.isEnabled || this.isShowing) {
return;
}
this.isShowing = true;
this.player =
this.animationBuilder
.build([
style({
opacity: '0',
zIndex : '9999'
}),
animate('200ms ease', style({opacity: '1'}))
]).create(this.loadingScreenEl);
this.isEnabled = true;
setTimeout(() => {
this.player.play();
setTimeout(() => {
this.isShowing = false;
}, 200);
}, wait);
}
hide() {
if (!this.isShowing
&& (!this.isEnabled || this.isHiding)) {
return;
}
this.isHiding = true;
this.player =
this.animationBuilder
.build([
style({opacity: '1'}),
animate('200ms ease', style({
opacity: '0',
zIndex : '-20'
}))
]).create(this.loadingScreenEl);
setTimeout(() => {
this.isEnabled = false;
this.player.play();
setTimeout(() => {
this.isHiding = false;
}, 200);
}, 0);
}
}
And I'm trying to use show/hide methods whenever I'm making a request to backend.
Here is what I got so far but I cannot find a way to properly put my subscriveLoading() method into intercept().
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { LoadingScreenService } from '../../core/services/loading-screen.service';
@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
constructor(
private loadingScreenService: LoadingScreenService
) {
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
}
private subscribeLoading(): Observable<any[]> {
this.loadingScreenService.show();
const observable;
observable.subscribe(() => {
this.loadingScreenService.hide();
}, err => {
this.loadingScreenService.hide();
return err;
}); // Pass the error to other observers
return observable;
}
}
Is there some easy way to use my LoadingScreenService to intercept every call and use show method form mentioned service while I'm waiting for response from backend?
Upvotes: 2
Views: 867
Reputation: 7221
Here is a way to use your service in an interceptor
On intercept you start to show your loader, then your intecept return the request with a finally operator that will hide the on success or error
@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
constructor(
private loadingScreenService: LoadingScreenService
) {
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.loadingScreenService.show();
return next.handle(req).pipe(finalize(() => {
this.loadingScreenService.hide();
}));
}
}
BUT : if you have two concurrent requests, when the first request will end, it will hide the loader even if the second request is not finished.
You should have a counter of pending request in your service :
@Injectable()
export class LoadingScreenService {
....
private counter: number: 0;
...
show(wait: number = 1000) {
this.counter++;
....
}
hide() {
this.counter--;
if (this.counter > 0) return;
...
}
Upvotes: 4