2

I have a component for the role of loading screen. I wanna show it during api calls.

loading-screen.component.html

<div *ngIf="isLoading | async" class="overlay">
 //Some html for the loading screen.
</div>

loading-screen.component.ts

isLoading: Subject<boolean> = this.loaderService.isLoading;

Btw when I set isLoading to true hardcoded, component fade in and I see my loading screen as it should be. So I assume there isn't anything wrong with this component.

loading-screen.interceptor.ts

@Injectable()
export class LoaderInterceptor implements HttpInterceptor {
  constructor(public loaderService: LoadingScreenService) { }
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this.loaderService.show();
    return next.handle(req).pipe(
        finalize(() => this.loaderService.hide())
    );
  }
}

I am not sharing the api call but it shouldn't be necessary since I see that show() and hide() methods triggered when I make my api call while debuging.

loading-screen.service.ts

 @Injectable({
  providedIn: 'root'
 })
 export class LoadingScreenService {

 isLoading = new Subject<boolean>();

 constructor() { }

 show() {
  this.isLoading.next(true);
 }

 hide() {
  this.isLoading.next(false);
 }
}

app.module.ts

providers: [
   LoadingScreenService,
   { provide: HTTP_INTERCEPTORS, useClass: LoaderInterceptor, multi: true }
 ]
2
  • In what way is this not working? Commented Dec 22, 2019 at 20:05
  • @WillAlexander It doesn't show any error, just nothing happens. The interesting part is that I can see the loading screen if I run "this.loaderService.isLoading.next(true);" in the component.ts. I guess my component can't get changes from service.ts Commented Dec 23, 2019 at 18:20

5 Answers 5

1

I found the problem. It seems I left a provider description in app.component.ts and it messed up everything without even giving an error. My bad.

Sign up to request clarification or add additional context in comments.

Comments

0

Make the following changes and you are good to go,

loading-screen.component.ts

loadingFlag : boolean;

constructor(private loaderService:loaderService){
this.loaderService.subscribe(value => (this.loadingFlag = value));
}

loading-screen.component.html

<div *ngIf="loadingFlag" class="overlay">
//Some html for the loading screen.
</div>

My First Answer in stackOverflow.

1 Comment

Thank you for your comment! Unfortunately I already tried this approach and doesn't seem like working. I don't get any error, just nothing happens. I just tried to put a button in my load-screen.component.html and run "this.loaderService.isLoading.next(true);" in the onClick of the button. It displayed the loading screen. I guess component does not get the changes which made in my service.ts cause it is working when I change the same value from my component.ts
0

Try changing its type from Subject to BehaviourSubject type on the LoadingScreenService and subscribe to it from the login component

add a BehaviourSubject on the loading service

isLoading:BehaviourSubject = new BehaviourSubject<boolean>();

in the component constructor or ngOnInit add subscription

this.loadingService.isLoading.subscribe(res=>{
 this.isLoading = res;
});

hope this helps

Comments

0

Dealing with loading as a boolean is over simplifying the problem. I think a better approach is to use array of Promise and check against it's length, where each promise represents the async task that is loading, and so only remove loading indicator when array of tasks is empty or when a task times out (or any other completion/cancelation logic).

class LoadingService {
    runningTasks : Promise[] = [];
    addTask(promise:Promise) { 
        //push to array and set timeout
        //await success/error to remove task
    }
}

Comments

0

Use separate broadcasting service

BroadcastService (broadcast.service.ts)

import { Injectable } from '@angular/core';

import { Subject, Subscription } from 'rxjs';
import { filter, map } from 'rxjs/operators';

@Injectable()
export class BroadcastService {
  private handler: Subject<any> = new Subject<any>();

  broadcast(type: string, action: any = null) {
    this.handler.next({ type, action });
  }

  subscribe(type: string, callback: (action: any) => void): Subscription {
    return this.handler
      .pipe(
        filter(info => info.type === type),
        map(info => info.action)
      )
      .subscribe(callback);
  }
}

This class acts as the event service bus for the entire application. Class registration is not required, as it is registered at the root level. Can be injected to the components.

Subscribe to events in app component

To show loading component

this.broadcastService.subscribe('SHOW_lOADING_COMPONENT', ()=>{
  this.isLoading= true;
});

To hide loading component

this.broadcastService.subscribe('HIDE_lOADING_COMPONENT', ()=>{
  this.isLoading= true;
});

Publish events inside components or services

get<T>(path: string, params: HttpParams): Observable<T> {

        this.broadcastService.broadcast('SHOW_lOADING_COMPONENT', null);

        return this.httpClient
            .get<T>(path, { headers: this.setHeaders(), params })
            .pipe(catchError(err => {

        this.broadcastService.broadcast('HIDE_lOADING_COMPONENT', null);

        this.handleError(err);
        return of<any>({ isSuccess: false, error: err });
            })
        );
    }

In app.component.html

<div *ngIf="isLoading | async" class="overlay">
 //Some html for the loading screen.
</div>
<router-outlet></router-outlet>

Note : In this way you can publish and subscribe to more and more events which directed the application with re-usability and loosely coupled approaches.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.