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

前端 未结 20 2211
逝去的感伤
逝去的感伤 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:21

    Using a list worked better for me

    import { Injectable } from '@angular/core';
    import { LoadingController } from '@ionic/angular';
    
    @Injectable({providedIn: 'root'})
    export class LoadingService {
        private loaders = new Array<HTMLIonLoadingElement>();
        constructor(public loadingController: LoadingController) { }
    
        present(options?: object) {
            if (this.loaders.length === 0) {
                this.loadingController.create(options).then(loader => {
                    this.loaders.push(loader);
                    loader.present();
                });
            }
        }
    
        async dismiss() {
            if (this.loaders && this.loaders.length > 0) {
                this.loaders.forEach(async loader => {
                    await loader.dismiss()
                        .then(() => {
                            loader = null;
                        })
                        .catch(e => console.log(e))
                        .finally(() => this.loaders = new Array<HTMLIonLoadingElement>());
                });
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-08 01:22

    After trying everything, here's what I finally came up with. Seems to be working well so far.

    Trying to make use of setInterval with a 500ms interval. I also tried to keep the function non-async so that it may be easily used in the consuming end.

    import { Injectable } from '@angular/core';
    import { LoadingController } from '@ionic/angular';
    
    @Injectable({ providedIn: 'root' })
    export class UiService {
        constructor(private loading: LoadingController) { }
    
        private loader: HTMLIonLoadingElement;
        private loaderLoading = false;
    
        public showLoading(message: string) {
            this.loaderLoading = true;
            this.loading.create({
                message,
                showBackdrop: true
            }).then(load => {
                this.loader = load;
                load.present().then(() => { this.loaderLoading = false; });
            });
        }
    
        public dismissLoading() {
            const interval = setInterval(() => {
                if (this.loader || !this.loaderLoading) {
                    this.loader.dismiss().then(() => { this.loader = null; clearInterval(interval)});
                } else if (!this.loader && !this.loaderLoading) {
                    clearInterval(interval);
                }
            }, 500);
        }
    }
    
    0 讨论(0)
  • 2020-12-08 01:23

    this is how I solved my issue..

    I used a boolean variable "isLoading" to change to false when dismiss() is called. after present() is finished if "isLoading" === false (means dismiss() already called) then it will dismiss immediately.

    also, I wrote the code in a service so I don't have to write it again in each page.

    loading.service.ts

    import { Injectable } from '@angular/core';
    import { LoadingController } from '@ionic/angular';
    
    @Injectable({
      providedIn: 'root'
    })
    export class LoadingService {
    
      isLoading = false;
    
      constructor(public loadingController: LoadingController) { }
    
      async present() {
        this.isLoading = true;
        return await this.loadingController.create({
          // duration: 5000,
        }).then(a => {
          a.present().then(() => {
            console.log('presented');
            if (!this.isLoading) {
              a.dismiss().then(() => console.log('abort presenting'));
            }
          });
        });
      }
    
      async dismiss() {
        this.isLoading = false;
        return await this.loadingController.dismiss().then(() => console.log('dismissed'));
      }
    }
    

    then just call present() and dismiss() from the page.

    the example in question:

    customer: any;
    
    constructor(public loading: LoadingService, private customerService: CustomerService)
    
    ngOnInit() {
      this.loading.present();
      this.customerService.getCustomer('1')
      .subscribe(
        customer => {
          this.customer = customer;
          this.loading.dismiss();
        },
        error => {
          console.log(error);
          this.loading.dismiss();
        }
      );
    
    0 讨论(0)
  • 2020-12-08 01:24

    I'm using a similar solution but relying on the Ids of the loading overlays and letting the Ionic Loading Controller manage what overlay should be on top.

    LoadingService

    import { Injectable } from '@angular/core';
    import { LoadingController } from '@ionic/angular';
    
    @Injectable({
      providedIn: 'root'
    })
    export class LoadingService {
    
      constructor(public loadingController: LoadingController) { }
    
      async present(loadingId: string, loadingMessage: string) {
        const loading = await this.loadingController.create({
          id: loadingId,
          message: loadingMessage
        });
        return await loading.present();
      }
    
      async dismiss(loadingId: string) {
        return await this.loadingController.dismiss(null, null, loadingId);
      }
    }
    

    Components/Services using the LoadingService

    import { LoadingService } from '../loading/loading.service';
    
    @Injectable({
      providedIn: 'root'
    })
    export class MessagesService {
    
      ...
    
      constructor(
        protected http: HttpClient,
        protected loading: LoadingService
      ) { }
    
      ...
    
      protected async loadMessagesOverview() {
        const operationUrl = '/v1/messages/overview';
    
        await this.loading.present('messagesService.loadMessagesOverview', 'Loading messages...');
    
        this.http.get(environment.apiUrl + operationUrl)
          .subscribe((data: Result) => {
            ...
            this.loading.dismiss('messagesService.loadMessagesOverview');
          }, error => {
            ...
            this.loading.dismiss('messagesService.loadMessagesOverview');
            console.log('Error getting messages', error);
          });
      }
    
    }
    
    
    0 讨论(0)
  • 2020-12-08 01:27

    Same issue I faced while using Ionic 4 loading controller. After trial and error I got working solution.

    As loading controller functions are using async and await because both are asynchronous functions.

    dismiss() function will called before present() function because, dismiss function will not wait until creating and presenting the loader, it will fire before present() as soon function will call.

    Below is working code,

       loading:HTMLIonLoadingElement;
       constructor(public loadingController: LoadingController){}
    
       presentLoading() {
         if (this.loading) {
           this.loading.dismiss();
         }
         return new Promise((resolve)=>{
           resolve(this.loadingController.create({
            message: 'Please wait...'
          }));
         })
       }
    
      async dismissLoading(): Promise<void> {
        if (this.loading) {
          this.loading.dismiss();
        }
      }
    
      someFunction(){
        this.presentLoading().then((loadRes:any)=>{
          this.loading = loadRes
          this.loading.present()
    
          someTask(api call).then((res:any)=>{
            this.dismissLoading();
          })
        })
      }
    
    0 讨论(0)
  • 2020-12-08 01:30

    I know this question is to ask about a year ago. I facing the same problem. I just want to post my solution. I hope the upcoming visitor will get help.

    async dismissLoading() {
        console.log("dismiss");
        this.isLoading = false;
      }
     private async presentLoading(msg) {
        console.log("loading");
        const loading = await this.loadingCtrl.create({
          message: msg,
        });
        await loading.present();
        var timer = setInterval(() => {
          if (!this.isLoading) {
            loading.dismiss();
            clearInterval(timer);
            console.log("set dismiss");
          }
        }, 1000);
      }
      async loadingmsg() {
        this.isLoading = true;
        await this.presentLoading("Please wait while...");
      }

    this solution work for me. Please correct me if I am wrong.

    0 讨论(0)
提交回复
热议问题