This is a simple Angular Service which handles multiple ionic 3 loaders at the same time. The most recent loader is displayed on top. If it is finished, and other loaders are still pending, the next recent will be shown.
File: loading.service.ts
typescript
/** @format */
import { Injectable } from '@angular/core';
import { Loading, LoadingController } from 'ionic-angular';
import { IntervalObservable } from 'rxjs/observable/IntervalObservable';
interface LoadingIndicator {
id: string | number;
message: string;
}
@Injectable()
export class LoadingService {
private loadingIndicators: Array<LoadingIndicator>;
private loader: Loading;
private isLoaderActive: boolean;
constructor(private loadingCtrl: LoadingController) {
console.log('LoadingProvider loaded.');
this.loadingIndicators = [];
this.createEmptyLoader();
this.isLoaderActive = false;
}
/**
* Add loading indicator on stack
* @param {LoadingIndicator} indicator
*/
public add(indicator: LoadingIndicator): void {
this.loadingIndicators.unshift(indicator);
this.handleLoaderVisibility();
}
/**
* Finish loading indicator by id
* @param {string | number} indicatorId
*/
public finish(indicatorId: string | number): void {
this.loadingIndicators = this.loadingIndicators.filter(indicator => {
// Hide loader before deleting
return indicator.id !== indicatorId;
});
this.handleLoaderVisibility();
}
/**
* Initialize empty loader
*/
private createEmptyLoader(): void {
this.loader = this.loadingCtrl.create({
content: ''
});
}
/**
* Determine which loader is currently visible
*/
private handleLoaderVisibility(): void {
// If has loaders, show message of most recent
if (this.loadingIndicators.length > 0) {
this.loader.setContent(this.loadingIndicators[0].message);
if (!this.isLoaderActive) {
console.warn('Creating instance');
this.loader.present();
this.isLoaderActive = true;
}
} else {
if (this.isLoaderActive) {
console.warn('Destroying instance');
this.setTimedSelfDestruction();
this.isLoaderActive = false;
}
}
}
/**
* Destroy loader after min 500ms to avoid flickering
* Do not destroy when another loader is pushed on stack in this time period
*/
private setTimedSelfDestruction(): void {
// This step is needed to avoid flickering loaders, which are invoked one by one
const sub = IntervalObservable.create(500).subscribe(() => {
// Check if loader has not been reactivated, then destroy,
// else self-instruction will be invoked again
if (!this.isLoaderActive) {
this.loader.dismiss();
this.createEmptyLoader();
sub.unsubscribe();
}
});
}
}