Ionic 4: “Loading Controller” dismiss() is called before present() which will keep spinner without dismissing

前端 未结 20 2212
逝去的感伤
逝去的感伤 2020-12-08 01:06

I used \"Ionic Loading Controller\" to show a spinner until the data is retrieved then it calls \"dismiss()\" to dismissed it. it works fine, but sometimes when the app alre

相关标签:
20条回答
  • 2020-12-08 01:39

    CHECK THIS OUT!

    After reading through these solutions I have come up with a solution that prevents loaders from stacking etc. It works great!

    import { Injectable } from '@angular/core';
    import { LoadingController } from '@ionic/angular';
    import { LoadingOptions } from '@ionic/core';
    import { TranslateService } from '@ngx-translate/core';
    import { isNil } from 'lodash-es';
    import { BehaviorSubject } from 'rxjs';
    import { filter } from 'rxjs/operators';
    
    enum LoadingTypeEnum {
      show,
      hide,
      message,
    }
    
    @Injectable({
      providedIn: 'root',
    })
    export class LoadingService {
      /**
       *  this is a special behavior subject we can use on an inital load to show or hide a background etc.
       *  EXAMPLE: on inital profile load, we might want to have ngIf on an overlay and simply listen for this event.
       */
    
      public appLoaded$ = new BehaviorSubject<boolean>(false);
      public loading$: BehaviorSubject<{ type: LoadingTypeEnum; data?: any }> = new BehaviorSubject<any>({ type: LoadingTypeEnum.hide });
      loadingState: { type: LoadingTypeEnum; data?: any } = null;
      public loading: HTMLIonLoadingElement = null;
      public loaderLoaded = false;
      public i;
      public spinningUp = false;
    
      constructor(private loadingController: LoadingController, private translate: TranslateService) {
        const l$ = this.loading$.pipe();
        l$.pipe(filter((l) => l.type === LoadingTypeEnum.show)).subscribe((l) => this.showLoading(l.data));
        l$.pipe(filter((l) => l.type === LoadingTypeEnum.hide)).subscribe(() => this.hideLoading());
      }
    
      show(opts?: LoadingOptions) {
        if (isNil(opts)) {
          opts = {
            message: 'Please wait...', // this.translate.instant('PLEASE_WAIT'),
          };
        }
        this.loading$.next({ type: LoadingTypeEnum.show, data: opts });
      }
    
      hide() {
        this.loading$.next({ type: LoadingTypeEnum.hide });
      }
    
      message(m: string) {
        this.loading$.next({ type: LoadingTypeEnum.message, data: m });
      }
    
      private async showLoading(opts: LoadingOptions) {
        if (!this.loading && !this.spinningUp) {
          this.spinningUp = true;
          this.loading = await this.loadingController.create(opts);
          await this.loading.present();
          this.spinningUp = false;
        }
      }
    
      private async hideLoading() {
        const t = setTimeout(() => {
          if (this.loading && !this.spinningUp) {
            this.loading.dismiss().then(() => {
              this.loading = null;
              this.spinningUp = false;
              clearTimeout(t);
            });
          }
        }, 1000);
      }
     
    }
    
    0 讨论(0)
  • 2020-12-08 01:42

    same problem here, and here my solution (ionic 4 and angular 7):

    Started from the acepted solution.

    the present creates the loading one time In the dismiss function, i set isShowing to false only if dimiss returns true

    import { Injectable } from '@angular/core';
    import { LoadingController } from '@ionic/angular';
    
    @Injectable({
      providedIn: 'root'
    })
    export class LoadingService {
    
      isDismissing: boolean;
      isShowing: boolean;
    
      constructor(public loadingController: LoadingController) { 
    
      }
    
      async present() {
        if(this.isShowing){
          return
        }
    
        this.isShowing = true
    
        await this.loadingController.create({spinner: "dots"}).then(re => {
          re.present()
          console.log("LoadingService presented", re.id)
        })
      }
    
      async dismiss() {
        if(this.isShowing){
          await this.loadingController.dismiss().then(res => {
            if(res){
              this.isShowing = false
              console.log("LoadingService dismissed", res);
            }
          })
        }
      }
    }
    
    0 讨论(0)
  • 2020-12-08 01:42

    Alternatively, you have to change the code where call loading like below

    async ngOnInit() {
      const loading = await this.loadingController.create();
      await loading.present();
      this.customerService.getCustomer('1')
      .subscribe(customer => {
        this.customer = customer;
        loading.dismiss();
      }
    }
    
    0 讨论(0)
  • 2020-12-08 01:43

    While the accepted solution can work... I think it is better to just have 1 loading always. My solution dismisses a previous loading, should it exist, and creates the new one. I usually only want to display 1 loading at a time (my particular usecase), so this solution works for me.

    The accepted solution poses the problem of possible orphaned loadings. But it is a good starting point

    0 讨论(0)
  • 2020-12-08 01:44

    for Ionic 4 check this solution

    Source Link

      import { Component } from '@angular/core';
      import { LoadingController } from '@ionic/angular';
    
      @Component({
        selector: 'app-home',
        templateUrl: 'home.page.html',
        styleUrls: ['home.page.scss'],
      })
      export class HomePage {
    
        loaderToShow: any;
    
        constructor(
          public loadingController: LoadingController
        ) {
        }
    
    
        showAutoHideLoader() {
          this.loadingController.create({
            message: 'This Loader Will Auto Hide in 2 Seconds',
            duration: 20000
          }).then((res) => {
            res.present();
    
            res.onDidDismiss().then((dis) => {
              console.log('Loading dismissed! after 2 Seconds');
            });
          });
        }
    
        showLoader() {
          this.loaderToShow = this.loadingController.create({
            message: 'This Loader will Not AutoHide'
          }).then((res) => {
            res.present();
    
            res.onDidDismiss().then((dis) => {
              console.log('Loading dismissed! after 2 Seconds');
            });
          });
          this.hideLoader();
        }
    
        hideLoader() {
          setTimeout(() => {
            this.loadingController.dismiss();
          }, 4000);
        }
    
      }
    
    0 讨论(0)
  • 2020-12-08 01:44

    I was facing the same issue, maybe I have an easier and more reliable solution using ionic events itself. This worked for me. It will wait until the loader is created and only then the service call will be done, and only when the service call is complete, only then the loader is dismissed. I hope this helps..

    yourFuncWithLoaderAndServiceCall(){
         this.presentLoading().then(()=>{
             this.xyzService.getData(this.ipObj).subscribe(
               res => {
                this.dismissLoading();
            this.dismissLoading().then(() => {
            this.responseObj = res;
                       })
                      }
                     });
                    }
    
    async presentLoading() {
        this.loader = await this.loadingController.create({
          translucent: true
        });
        await this.loader.present();
      }
    
      async dismissLoading() {
        await this.loader.dismiss();
      }
    
    0 讨论(0)
提交回复
热议问题