はじめに
Angular4.3で追加されたHttpClientのInterceptorという機能を使うことで、HttpClientを使ったWebAPI呼び出しのタイミングで実行したい共通処理を定義することができます。
今回はこのInterceptor機能を使うことでAPIの呼び出し中にスピナーを表示する処理を実装します。
バージョン情報
CSSフレームワークとして、Angular Materialを使用しています。
- Angular v7.2.0
- firebase: v6.3.4
- Angular Material v7.3.7
開発
スピナーコンポーネントとスピナーサービス、インターセプターを作成することでスピナーの表示処理を実装します。
HTTPリクエストを検知したインターセプターから受け取った、true/false
の値をスピナーサービス経由でスピナーコンポーネントに渡してスピナーの表示/非表示を切り替えるといった流れになります。
AppModuleの設定
まず、AppModuleのimports[]
にAngular MaterialのProgress spinner と AngularのHttpClientModuleを追加します。
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { HttpClientModule } from '@angular/common/http'; //...省略 @NgModule({ //...省略 imports: [ HttpClientModule, MatProgressSpinnerModule, ], //...省略 }) export class AppModule {}
スピナーコンポーネントの作成
スピナーのコンポーネントクラスを作成していきます。
スピナーコンポーネントでは、インターセプターから渡させたbooleanの値をもとにスピナーの表示と非表示を実施します。
color
, mode
, value
はスピナーの色などを設定するAngular Material Spinnerのプロパティになります。
isLoading
はスピナーの表示・非表示を制御する変数で詳細は後述します。
スピナーコンポーネントのHTMLファイルです。
isLoading
はSubject
型なので、コンポーネント側でsubscribe
するかasync
パイプを使用する必要があります。
スピナーコンポーネントのレイアウトを設定するSCSSファイルです。
スピナーサービスの作成
続いてスピナーサービスを作成します。
show
とhide
メソッドを経由して、isLoading
にtrue/false
を渡すことで、スピナーの表示・非表示を切り替えています。
インターセプターの作成
インターセプターSpinnerInterceptor
を作成します。
HTTP リクエストが始まったタイミングでSpinnerService
のshow
メソッドを呼び出してスピナーを表示し、リクエストが完了したタイミングでhide
メソッドを呼び出してスピナーを消しています。
AppModuleの設定
AppModuleのproviders: []
に作成したスピナーサービスとインターセプターを追加します。
providers: [ SpinnerService, { provide: HTTP_INTERCEPTORS, useClass: SpinnerInterceptor, multi: true } ],
最後にapp.component.html
にスピナーコンポーネントを追加して、スピナーの実装は完了です。
<app-spinner></app-spinner> <router-outlet></router-outlet>
動作確認
実装が正しくできているか確認します。
HttpClientによるHTTPリクエスト
ここまでの実装が正しくできていれば、HttpClientを介してHTTPリクエストを実施するとスピナーが表示され、リクエストが完了するとスピナーが消えます。
下のコードでは、yesno.wtf APIをHttpClientで呼び出しているため、リクエストの間、スピナーが表示されます。
// ...省略 import { HttpClient } from '@angular/common/http'; export class LoginComponent implements OnInit { constructor( private http: HttpClient ) {} public ngOnInit() { this.http .get(`https://yesno.wtf/api`) .subscribe(response => console.log(response)); }
HttpClientを使わない場合
Firebaseへのアクセスなどの、Angular HttpClientを使用しないHTTPアクセスの場合は、インターセプターが反応しません。そのため、直接SpinnerService
のメソッドを叩いてスピナーを表示・非表示する必要があります。
下記のFirebase認証を実施しているコードでは、処理が開始したタイミングでshow
メソッドでスピナーを表示し、処理が完了(finally
)したタイミングでhide
メソッドを呼び出すことでスピナーを消しています。
public onSubmit() { // メールアドレスとパスワードをFirebase Authenticationに渡す // スピナーを表示する this.spinnerService.show(); this.afAuth.auth .signInWithEmailAndPassword( this.emailControl.value, this.passwordControl.value ) // ログインに成功したらホーム画面に遷移する .then(user => { this.router.navigate(['/home']); }) // ログインに失敗したらエラーメッセージをログ出力 .catch(error => { console.log(error); this.apiErrorMessage = error ? error.message : undefined; }) // 処理が完了したら、スピナーを非表示にする .finally(() => this.spinnerService.hide()); }
参考サイト
Display a loader on every HTTP request using Interceptor in Angular 7 - First Class JS