user10668235
user10668235

Reputation:

Angular 8 spinner or loader using unrelated components

Here is my code below StaffMembers.ts component.

import { Component, OnInit } from '@angular/core';
import { StaffService } from '../_services/Staff.service';
import { Router, NavigationExtras } from "@angular/router";

@Component({
  selector: 'StaffMembers',
  templateUrl: './StaffMembers.html'
})

export class StaffMembers implements OnInit {
  public StaffArr: Array<any>;
  constructor(private _StaffService: StaffService, private _router: Router) {
  }

  async ngOnInit() {
    this.StaffArr = await this._StaffService.GetStaff();
  }
}

Here is my Staff.service.ts service component below.

import { Injectable, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { HostedPathConst } from '../_helpers/path';

@Injectable({
  providedIn: 'root'
})
export class StaffService {
  private messageStaffSource: BehaviorSubject<Staff>;
  public currentStaffMessage: Observable<Staff>;
  private _Staff: Staff;
  private ProfileFile: FileList;
  private sL: Array<Staff> = new Array();


  constructor(private http: HttpClient, private toastr: ToastrService) {
    this.messageStaffSource = new BehaviorSubject<Staff>(new Staff());
    this.currentStaffMessage = this.messageStaffSource.asObservable();
  }

  GetStaff(): Promise<any> {
    const promise = this.http.get(HostedPathConst.HostedPath + `Staff/GetStaff`).toPromise();
    return promise;
  }

  Error(data) {
  }
  Success(data) {
    this.toastr.success(data.errorMessage, 'Success !');
  }
}

Now as i want to add my loader on the page i have found a package from this URL which is working as expected.
https://www.npmjs.com/package/@tusharghoshbd/ngx-loader

As i use it in any HTML page its called by this way.

<ngx-loader [show]="show" [fullScreen] = "fullScreen" [template]="template"> Loading... </ngx-loader>

and in any component file its called like this way.

  //Declaration
  show = false;
  fullScreen = true;
  template = ``
   //Initialization
  this.show = true;
  this.fullScreen = true;
  this.template = ``;
  //And to stop the loader
  this.show = false

Now as i have above two unrelated components StaffMembers.ts for html component and for service Staff.service.ts now as i want to use the spinner or loader when the data is being fetched from the

async ngOnInit() {
    this.StaffArr = await this._StaffService.GetStaff();
  }

How can i wait for my data being loaded to start and stop the loader or spinner.

Upvotes: 1

Views: 842

Answers (1)

Athanasios Kataras
Athanasios Kataras

Reputation: 26372

If you want to keep them separated (and you should) I would use an http interceptor.

There is an excellent example on medium: https://medium.com/swlh/angular-loading-spinner-using-http-interceptor-63c1bb76517b

Check the code:

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor, HttpResponse
} from '@angular/common/http';
import { Observable } from 'rxjs';
import {catchError, map} from 'rxjs/operators'
import {LoadingService} from '../../layout/services/loading/loading.service';

/**
 * This class is for intercepting http requests. When a request starts, we set the loadingSub property
 * in the LoadingService to true. Once the request completes and we have a response, set the loadingSub
 * property to false. If an error occurs while servicing the request, set the loadingSub property to false.
 * @class {HttpRequestInterceptor}
 */
@Injectable()
export class HttpRequestInterceptor implements HttpInterceptor {

  constructor(
    private _loading: LoadingService
  ) { }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this._loading.setLoading(true, request.url);
    return next.handle(request)
      .pipe(catchError((err) => {
        this._loading.setLoading(false, request.url);
        return err;
      }))
      .pipe(map<HttpEvent<any>, any>((evt: HttpEvent<any>) => {
        if (evt instanceof HttpResponse) {
          this._loading.setLoading(false, request.url);
        }
        return evt;
      }));
  }
}

In this example, the author uses a service to share change in state. You could use events too, but it would be trickier as it's out of the running scope of angular

Upvotes: 1

Related Questions