IONIC 4 : Loading Controller, dismiss() is called before present() which will keep spinner without dismissing

I am using Ionic 4 and trying to implement loadingcontroller as a service and want to use in multiple pages.
I followed the solution provided here. But the solution seem to have hardcoded with the delay of 5000. In realtime that is not an effective way of doing right. Can someone please recommend the approach that I have to take to achieve it.

What do you want instead of the hardcoded 5000?
You say, “recommend the approach that I have to take to achieve it”. What do you mean by “it”? What are you trying to achieve?

@VictorNorman Thanks for your time. I want to create a service that instantiates a loader and presents it. I also want to write a method as part of service to dismiss it. The approach given in the link shared uses delay of 5 seconds while presenting it. In real world scenarios we should not hard code the value as the response time depends on the data speed, data that is being passed over the wire and the network speed. So when I try to remove the delay from the logic and run the app the loading icon stay for ever. Do you know how to solve the problem?

One way I know is
async startLoad(options: any = {}): Promise {
return await this.loadCtrl.create(options);
}

const loader = await this.loadingSvc.startLoad();
await loader.present();
// do some stuff
await loader.dismiss();

But if I follow this approach I will end up creating variable for loader in every page which I feel is little dirty. Is there a better way to solve the problem?

Hope you understood what I’m trying to achieve, thanks in advance :slight_smile:

If you will only every present one loading controller, and I think that’s a good assumption, then I guess you could just store the result of this.loadCtrl.create() in a variable in the service. You could have the function present the loading controller too. Then, when you call dismiss, it uses the stored variable and dismisses that. You code that uses it would look something like this:

await this.loadingSvc.presentLoading(); // it creates the loading thing and presents it. and stores the actual controller in a variable in “this”
// do stuff
this.loadingSvc.close(); // service calls this.theLoader.dismiss(), assuming the local variable was called theLoader.

Hope you understand. if not, I could probably code it up for you.

Hi @VictorNorman,

Did you mean something like this?

Service

loader:HTMLIonLoadingElement;
  constructor(private loadingController: LoadingController) { }

  async presentLoader(options: any = {}) {
    this.loader = await this.loadingController.create(options);
    await this.loader.present();
  }

  async dismissLoader() {
      await this.loader.dismiss()
      .then(()=>{
        this.loader = null;
      })
      .catch(e => console.log(e));
  }

Controller:
this.service.presentLoader() and this.service.dismissloader() from the page. Is it?
Thats when I ended up with the issue mentioned in the title of this question. Please correct me if I am going wrong somewhere.

1 Like

Yes, I understand your problem now. Perhaps if you changed

await this.loader.present();

to just

this.loader.present();

Then it would put the spinner up there but wouldn’t wait before returning control to the caller. I think.

Create a service

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 loadingPresent() {
    this.isLoading = true;
    return await this.loadingController.create({
      message: 'Please wait ...',
      spinner: 'circles' 
    }).then(a => {
      a.present().then(() => {
        console.log('loading presented');
        if (!this.isLoading) {
          a.dismiss().then(() => console.log('abort laoding'));
        }
      });
    });
  }

  async loadingDismiss() {
    this.isLoading = false;
    return await this.loadingController.dismiss().then(() => console.log('loading dismissed'));
  }
}

sample use :

home.page.ts

getData() { 
    this.loadingService.loadingPresent();
    // ...
    // ...
    this.loadingService.loadingDismiss();
}

and it’s work :slight_smile:

4 Likes

Hi, I am the one who wrote the solution in stackoverflow and I saw your question when I was checking ionic summary by coincidence :slight_smile: .

Anyway you can achieve what you want by only removing “duration: 5000,” from my code.
I only added this duration in case it took the server more than 5 seconds to respond.
Without it it will work as you want it to work.

God luck

I found a new way to do this. I hope it help!
It’s using the id of loading. So if you have many loadings you don’t want to dismiss wrong loading.

In the service:

  async showLoading(loadingId: string, loadingMessage: string = 'Loading...') {
    const loading = await this.loadingCtrl.create({
      id: loadingId,
      message: loadingMessage,
      spinner: 'circles'
    });
    return await loading.present();
}

  async dismissLoader(loadingId: string) {
      return await this.loadingCtrl.dismiss(null, null, loadingId).then(() => console.log('loading dismissed'));
  }

In the component calling the loading:

await this.globalVars.showLoading('ifOfLoading')

Dismissing the loading:

this.globalVars.dismissLoader('ifOfLoading')

For the first time if loadingDismiss in called before presenting is complete, you will get an error in console.

Use following code to take care of this scenario:

async loadingDismiss() {
        this.isLoading = false;
        return await this.loadingController.getTop().then(a => {
           if ( a )
            a.dismiss().then(() => console.log('loading dismissed'));
        });

    }