【问题标题】:Cannot Dismiss LoadingController In Error Response Of Subscribe() - Ionic 4无法在 Subscribe() 的错误响应中关闭 LoadingController - Ionic 4
【发布时间】:2020-06-17 04:48:36
【问题描述】:

当用户尝试登录时,我正在显示一个 LoadingController。同时,正在调用 API。

当我从 subscribe 收到 SUCCESS 响应时,我可以关闭 LoadingController,但是当我收到 ERROR 响应时,我无法关闭。请帮忙!

我是一名专业的 Python 开发人员,也是 Ionic 的新手,一天前才开始。所以,请提供帮助。

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();
    }

  }

}

【问题讨论】:

  • 尝试调试并确保您的控件在出错时进入错误块。您的服务器可能会发送带有自定义错误消息的 200。或者你可以dismiss你在complete回调中的加载,只需在错误块后附加() => { ... }
  • 我认为您不需要最后一个 this.loadingController.dismiss()。加载控制器可能在您的 API 还没有返回之前就被关闭了。

标签: javascript angular typescript ionic-framework ionic4


【解决方案1】:

没有任何服务,

我在使用 Ionic 4 加载控制器时遇到了同样的问题。 经过反复试验,我得到了有效的解决方案。

由于加载控制器函数正在使用 async 和 await,因为它们都是异步函数。

dismiss() 函数将在present() 函数之前调用,因为dismiss 函数不会等到创建和呈现加载器,它会在present() 函数调用之前触发。

下面是工作代码,

   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();
      })
    })
  }

【讨论】:

    【解决方案2】:
    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();
        });
    

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

    【讨论】:

    • 在没有互联网连接时不起作用。 (在错误块内时)
    • 您的 API 在没有 Internet 连接的情况下可用?
    • 没有,我只是关掉了网络,然后尝试登录。
    【解决方案3】:

    使用 Angular 属性绑定。为您的加载创建一个组件:

    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) {}
    }
    

    ...然后在“login.page.html”中使用您的组件:

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

    ...在“LoginPage”中创建一个属性“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;
        }
      }
    }
    

    这对我有用,我在其他页面上重用加载组件!

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

    【讨论】:

      【解决方案4】:

      我实际上遇到了这个确切的问题,对我来说答案就是使用await

      用于创建和关闭加载器的函数都会返回 Promise。我意识到正在发生的是订阅/承诺拒绝正在阻止所有其他承诺完成。现在,我只是等待展示和解雇,我没有问题:

      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();
      }
      

      我希望这个简单的解决方案有所帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-18
        • 2011-05-04
        • 1970-01-01
        • 1970-01-01
        • 2020-02-04
        • 2020-12-21
        • 1970-01-01
        相关资源
        最近更新 更多