Multiple loading indicators shown above each other

Issue

I have an app made in ionic 3 in which I created a provider to centralize access to LoadingController.

I have implemented the provider as the code shown below, and I thought it’d be enough to control loading indicators for everywhere in the app.

I don’t know how, but sometimes there are multiple instances of the indicator being instantiated, even with the if (!this.isShowing()) verification before instantiating a new one.

Can someone help me figure out what is happening? Thanks in advance.

import { Injectable } from '@angular/core';
import { LoadingController, Loading, Platform } from 'ionic-angular';
import { BehaviorSubject } from 'rxjs';

export enum LoadingStatus {
  SHOWING,
  DISMISSED,
}

@Injectable()
export class LoadingProvider {
  private loading: Loading = null;
  private status: BehaviorSubject<LoadingStatus> = new BehaviorSubject(LoadingStatus.DISMISSED);

  constructor(private loadingCtrl: LoadingController, private platform: Platform) {
    this.platform.ready().then(() => {
      this.status.next(LoadingStatus.DISMISSED);
    });
  }

  async show(content?: string) {
    if (!this.isShowing()) {
      this.create(content);
      await this.loading.present();
    }
  }

  async dismiss() {
    if (this.isShowing()) {
      await this.loading.dismiss();
      this.loading = null;
    }
  }

  private create(content?: string) {
    this.loading = this.loadingCtrl.create({
      content: content ? content : 'Carregando...',
      showBackdrop: true,
      enableBackdropDismiss: true,
    });

    this.loading.didEnter.subscribe(() => {
      if (this.status.getValue() === LoadingStatus.DISMISSED) {
        this.updateLoadingStatus(LoadingStatus.SHOWING);
      }
    });

    this.loading.didLeave.subscribe(() => {
      if (this.status.getValue() === LoadingStatus.SHOWING) {
        this.updateLoadingStatus(LoadingStatus.DISMISSED);
      }
    });
  }

  private async updateLoadingStatus(status: LoadingStatus) {
    this.status.next(status);
  }

  private isShowing(): boolean {
    return this.status.getValue() === LoadingStatus.SHOWING;
  }
}

Solution

You’re not updating your loading status until after the loader enters. If the entering is asynchronous, you’ve got a possibility for a race condition:

  1. show() is called
  2. A loader is created
  3. show() is called again by something else
  4. A second loader is created
  5. The first loader enters, updating the status

Answered By – frodo2975

Answer Checked By – Timothy Miller (AngularFixing Admin)

Leave a Reply

Your email address will not be published.