简体   繁体   English

无法在 Subscribe() 的错误响应中关闭 LoadingController - Ionic 4

[英]Cannot Dismiss LoadingController In Error Response Of Subscribe() - Ionic 4

I'm displaying a LoadingController when the user tries to login.当用户尝试登录时,我正在显示 LoadingController。 Meanwhile, an API is being called.同时,正在调用 API。

I'm able to dismiss the LoadingController when I get a SUCCESS response from subscribe, but when I get an ERROR response, I'm not able to dismiss.当我收到来自订阅的 SUCCESS 响应时,我可以关闭 LoadingController,但是当我收到 ERROR 响应时,我无法关闭。 Please help!请帮忙!

I'm a professional Python developer and a total newbie to Ionic, just started a day ago.我是一名专业的 Python 开发人员,也是 Ionic 的新手,一天前刚刚开始。 So, please assist as such.所以,请协助。

import { Component, OnInit } from '@angular/core';
import { ToastController, LoadingController } from '@ionic/angular';

import { CallapiService } from '../callapi.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.page.html',
  styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {

  userEmail = '';
  userPassword = '';
  loginUrl = 'login/';
  loginMethod = 'POST';
  postBody = {};


  constructor(
    public toastController: ToastController,
    public loadingController: LoadingController,
    private callApiService: CallapiService,
  ) { }

  ngOnInit() {
  }

  async presentToast(displayMessage) {
    const toast = await this.toastController.create({
      message: displayMessage,
      duration: 2000,
      position: 'middle',
    });
    return await toast.present();
  }

  async presentLoading(loadingMessage) {
    const loading = await this.loadingController.create({
      message: loadingMessage,
    });
    return await loading.present();
  }


  loginUser() {
    if (this.userEmail === '' || this.userPassword === '') {
      this.presentToast('Email and password are required.');
    }

    else {
      this.presentLoading('Processing...');
      this.postBody = {
        email: this.userEmail,
        password: this.userPassword,
      };
      this.callApiService.callApi(this.loginUrl, this.postBody, this.loginMethod).subscribe(
        (success) => {
          console.log(success);
          this.loadingController.dismiss();
        },
        (error) => {
          console.log(error);
          this.loadingController.dismiss();
        }
      );
      this.loadingController.dismiss();
    }

  }

}

Without any service,没有任何服务,

Same issue I faced while using Ionic 4 loading controller.我在使用 Ionic 4 加载控制器时遇到的同样问题。 After trial and error I got working solution.经过反复试验,我得到了有效的解决方案。

As loading controller functions are using async and await because both are asynchronous functions.由于加载控制器函数使用 async 和 await,因为它们都是异步函数。

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. dismiss() 函数将在 present() 函数之前调用,因为dismiss 函数不会等到创建和呈现加载器,它会在present() 函数调用之前触发。

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();
      })
    })
  }
this.callApiService.callApi(this.loginUrl, this.postBody, this.loginMethod)
  .subscribe(
    (data) => {
      // Called when success  
    },
    (error) => {
      // Called when error
    },
    () => {
      // Called when operation is complete (both success and error)
      this.loadingController.dismiss();
    });

Source: https://stackoverflow.com/a/54115530/5442966来源: https : //stackoverflow.com/a/54115530/5442966

Use Angular property binding.使用 Angular 属性绑定。 Create a component to your loading:为您的加载创建一个组件:

import { Component, Input } from '@angular/core';
import { LoadingController } from '@ionic/angular';

@Component({
  selector: 'app-loading',
  template: ''
})
export class LoadingComponent {
  private loadingSpinner: HTMLIonLoadingElement;

  @Input()
  set show(show: boolean) {
    if (show) {
      this.loadingController.create().then(loadingElem => {
        this.loadingSpinner = loadingElem;
        this.loadingSpinner.present();
      });
    } else {
      if (this.loadingSpinner) {
        this.loadingSpinner.dismiss();
      }
    }
  }

  constructor(private loadingController: LoadingController) {}
}

...then in 'login.page.html' use your componente: ...然后在“login.page.html”中使用您的组件:

...    
<app-loading [show]="showLoading"></app-loading>

... in 'LoginPage' create a property 'showLoading' and set it to true or false where you whant: ...在“登录页面”中创建一个属性“showLoading”并将其设置为 true 或 false 您想要的:

//.... some source code
export class LoginPage implements OnInit {
  showLoading;
  userEmail = '';
  userPassword = '';
  loginUrl = 'login/';
  loginMethod = 'POST';
  postBody = {};

  //.... some source code

  loginUser() {
    if (this.userEmail === '' || this.userPassword === '') {
      this.presentToast('Email and password are required.');
    } else {
      this.showLoading = true;
      this.postBody = {
        email: this.userEmail,
        password: this.userPassword
      };
      this.callApiService
        .callApi(this.loginUrl, this.postBody, this.loginMethod)
        .subscribe(
          success => {
            console.log(success);
            this.showLoading = false;
          },
          error => {
            console.log(error);
            this.showLoading = false;
          }
        );
      this.showLoading = false;
    }
  }
}

This works for me, I reuse the loading component on others pages!这对我有用,我在其他页面上重用加载组件!

Recommended reading: https://angular.io/start推荐阅读: https : //angular.io/start

I actually ran into this exact issue and for me the answer was just to use await .我实际上遇到了这个确切的问题,对我来说答案就是使用await

The functions for both creating and dismissing loaders return promises.用于创建和解除加载器的函数返回承诺。 What I realized was happening is that the subscribe/promise rejection was halting all other promises from completing.我意识到正在发生的是订阅/承诺拒绝正在阻止所有其他承诺完成。 Now, I just await both presenting and dismissing and I have no issue:现在,我只是等待呈现和解散,我没有问题:

async getData() {  
  //await presenting
  await this.presentLoading('Loading...');

  try {
    let response = await this.httpService.getData();
    await this.loadingController.dismiss();

    //...
  catch(err) {
    this.loadingController.dismiss();
    //handle error
    //...
  }
}

async presentLoading(msg: string) {
  const loading = await this.loadingController.create({
    spinner: 'crescent',
    message: msg
  });
  await loading.present();
}

I hope this simple solution helps!我希望这个简单的解决方案有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM