IonicのLoadingControllerをObservableで扱う


前置き

RxJSを勉強してある程度使えるようになり、
async/awaitは全部ぶっ潰したくなる病になってしまったが、
ionicのコンポーネントは公式で紹介されている書き方がほとんどasync/await。

page.tsの中のapi取得処理はObservableで書いており、
ObservableとPromiseの混在が気持ち悪かったので
Loading処理をObservableで使えるようにしてみた。

ion-loading公式ドキュメント

loadingのserviceを作成する

loader.service.ts
import { Injectable } from "@angular/core";
import { LoadingController } from "@ionic/angular";
import { Observable, from } from "rxjs";
import { flatMap, finalize } from "rxjs/operators";

@Injectable({
    providedIn: "root"
})
export class LoaderService {
    private loader = null;

    constructor(public loadingController: LoadingController) {}

    loading(obs$: Observable<any>): Observable<any> {
        return from(this.openLoader()).pipe(
            // ローディングを表示した後、引数で渡したobservable処理を開始
            flatMap(() => obs$),
            // 引数で渡したobservable処理が終わったらローディング表示が消える
            finalize(() => this.closeLoader())
        );
    }

    private async openLoader(): Promise<void> {
        if (this.loader == null) {
            this.loader = await this.loadingController.create({});
        }

        await this.loader.present();
    }

    private async closeLoader(): Promise<void> {
        if (this.loader == null) return null;

        await this.loader.dismiss();
        this.loader = null;
    }
}

各ページでのローディング記述

hoge.page.ts
fetchData(param) {
    // API取得処理を定義して変数に格納
    const obs$ = this.search(param).pipe(
        tap(data => this.data = data)
    );

    // 定義したObservable処理をloadingServiceに渡してsubscribe
    this.loaderService.loading(obs$).subscribe();
}