iT邦幫忙

2024 iThome 鐵人賽

DAY 25
0

為了視覺化呈現 API 取得的進度,也避免使用者一直重複點擊按鈕,所以利用 Http interceptor,來裝上 Loading畫面。

Loading 畫面如果懶得自己刻,可以去 cssload.net 看看

LoadingInterceptor

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

@Injectable()
export class LoadingInterceptor implements HttpInterceptor {

  private requests: HttpRequest<any>[] = [];
  private whiteList: string[] = [];

  constructor(private loadingService: LoadingService) { }

  isInWhiteList(url: string): boolean {
    let result = false;

    if (url) {
      for (const whiteUrl of this.whiteList) {
        if (url.includes(whiteUrl)) {
          result = true;
          break;
        }
      }
    }

    return result;
  }

  removeRequest(req: HttpRequest<any>): void {
    if (!this.isInWhiteList(req.url)) {
      const i = this.requests.indexOf(req);
      if (i >= 0) {
        this.requests.splice(i, 1);
      }

      if (this.requests.length === 0) {
        this.loadingService.loading(false);
      }
    }
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (!this.isInWhiteList(req.url)) {
      if (this.requests.length === 0) {
        this.loadingService.loading(true);
      }
      this.requests.push(req);
    }

    return new Observable(observer => {
      const subscription = next.handle(req)
        .subscribe(
          event => {
            if (event instanceof HttpResponse) {
              this.removeRequest(req);
              observer.next(event);
            }
          },
          err => { this.removeRequest(req); observer.error(err); },
          () => { this.removeRequest(req); observer.complete(); });

      // teardown logic in case of cancelled requests
      return () => {
        this.removeRequest(req);
        subscription.unsubscribe();
      };
    });
  }
}

LoadingService

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

@Injectable({
  providedIn: 'root'
})
export class LoadingService {
  private _isLoading: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

  // 使 isLoading 可以被其他組件訂閱
  public readonly isLoading$ = this._isLoading.asObservable();

  constructor() { }

  // 控制加載指示器的顯示和隱藏
  loading(isVisible: boolean): void {
    this._isLoading.next(isVisible);
  }
}

上一篇
Day24:前後端串接-底層Service
下一篇
Day26:家具依API展示
系列文
收納規劃APP32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言