Ionic 3 Angular 4 HTTP拦截器以在每个请求中显示加载状态

7

我正在尝试制作一个自定义的http拦截器,用于处理加载和其他附加功能。(为每个请求手动处理加载会显着增加代码量)。

问题在于:加载程序在每个请求上都被激活,但loading.dismiss()不起作用。(加载旋转器仍然处于活动状态,没有错误)

我的配置:

http拦截器:

@Injectable()
export class MyHttpWrapper extends Http {
  private loading: any;

  constructor(connectionBackend: ConnectionBackend, requestOptions: RequestOptions,private loadingCtrl: LoadingController) {
    super(connectionBackend, requestOptions);
  }

  public get(url: string, options?: RequestOptionsArgs): Observable<Response> {
    this.showLoader();

    return super.get(url, this.getRequestOptionArgs(options))
      .finally<Response>(() => {
        this.hideLoader();
      });
  }

  public post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
      return super.post(url, body, options);
  }

  public put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
    return super.put(url, body, options);
  }

  public delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
    return super.delete(url, options);
  }


  private getRequestOptionArgs(options?: RequestOptionsArgs) : RequestOptionsArgs {
    if (options == null) {
      options = new RequestOptions();
    }
    if (options.headers == null) {
      options.headers = new Headers();
    }
    options.headers.append('Content-Type', 'application/json');

    return options;
  }


  private showLoader() {
    if(!this.loading){
      this.loading = this.loadingCtrl.create({
        dismissOnPageChange: true
      });
    }
    this.loading.present();
    console.log('show loader')
  }
  private hideLoader() {
    console.log('hide loader')
    console.log(this.loading)
    this.loading.dismiss();
  }
}

app.module.ts

export function httpInterceptorFactory(xhrBackend: XHRBackend, requestOptions: RequestOptions, loadingCtrl: LoadingController) {
  return new MyHttpWrapper(xhrBackend, requestOptions, loadingCtrl);
}
    @NgModule({
      declarations: [
        MyApp
      ],
      imports: [
        BrowserModule,
        HttpModule,
        IonicModule.forRoot(MyApp),
        IonicStorageModule.forRoot()
      ],
      bootstrap: [IonicApp],
      entryComponents: [
        MyApp
      ],
      providers: [
        StatusBar,
        SplashScreen,
        {provide: ErrorHandler, useClass: IonicErrorHandler},
        {provide: APP_CONFIG, useValue: AppConfig},
        {
          provide: Http,
          useFactory: httpInterceptorFactory,
          deps: [XHRBackend, RequestOptions, LoadingController]
        }
      ]
    })
    export class AppModule {}

更新:

尝试添加简单服务(并在MyHttpWrapper中使用它),但没有改变任何内容,仍然存在同样的问题。

@Injectable()
export class LoadingService {
  private loading:any;

  constructor(private loadingCtrl: LoadingController) {

  }

  show() {
    if(!this.loading){
      this.loading = this.loadingCtrl.create({
        dismissOnPageChange: true
      });
    }
    this.loading.present();
  }
  hide() {
    if (this.loading) {
      this.loading.dismiss();
    }
  }
}

尝试使用 private static loading: any; - Duannx
同样。实际上,我认为这并不正确——每个类的实例必须具有唯一的属性。 - user1935987
我真的看不出将MyHttpWrapper设置为单例的理由。虽然在providers中导入了单例的LoadingService,但这并没有改变什么。 - user1935987
我认为当您订阅Observable时,会创建MyHttpWrapper的一个实例,并且它与显示加载的实例不同,因此它无法解除加载。 - Duannx
那不是那样的。 - user1935987
显示剩余2条评论
1个回答

2

我正在Ionic 3应用中使用以下自定义HTTP拦截器:

这是loader.ts文件:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import { LoadingController } from 'ionic-angular';

@Injectable()
export class LoaderProvider {

  constructor(public http: Http, public loadingCtrl: LoadingController) {

  }

  loading: any = this.loadingCtrl.create({
    content: "Please wait..."
  })

  show() {
    this.loading.present();
  }

  hide() {
    this.loading.dismiss();
  }


}

这是HTTP拦截器。
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/Rx';

import { LoaderProvider } from '../loader/loader';

/*

Ionic 3 HTTP interceptor
Author: iSanjayAchar (@iSanjayAchar) <sanjaychar@gmail.com>

*/

@Injectable()

export class httpService {

  baseUrl: string = 'https://yourbaseurl.in'

  constructor(public http: Http, private loader: LoaderProvider) {

  }

  get(url) {
    this.loader.show();
    return this.http.get(this.baseUrl + url)
      .map(resp => resp.json())
      .finally(() => {
        this.loader.hide();
      });
  }

  post(url, body) {
    this.loader.show();
    return this.http.post(this.baseUrl + url, body)
      .map(resp => resp.json())
      .finally(() => {
        this.loader.hide();
      });
  }

  put(url, body) {
    this.loader.show();
    return this.http.put(this.baseUrl + url, body)
      .map(resp => resp.json())
      .finally(() => {
        this.loader.hide();
      });
  }

  delete(url) {
    this.loader.show();
    return this.http.delete(this.baseUrl + url)
      .map(resp => resp.json())
      .finally(() => {
        this.loader.hide();
      });
  }

  patch(url, body) {
    this.loader.show();
    return this.http.patch(this.baseUrl + url, body) 
      .map(resp => resp.json())
      .finally(() => {
        this.loader.hide();
      });
  }
}

现在最后,将其导入而不是使用http everywhere,示例如下。
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { Http, Headers, RequestOptions } from '@angular/http';
import { ToastController } from 'ionic-angular';
import 'rxjs/add/operator/map';
import { AlertController } from 'ionic-angular';
import { httpService } from '../../providers/http/http';

/**
 * Generated class for the LoginPage page.
 *
 * See http://ionicframework.com/docs/components/#navigation for more info
 * on Ionic pages and navigation.
 */

@IonicPage()

@Component({
  selector: 'page-login',
  templateUrl: 'login.html',
})

export class LoginPage {
  isLoginIn: boolean = false;

  user: any = {
    email: '',
    password: ''
  }


  constructor(private http: httpService, private toast: ToastController) {

  }

 login() {

    this.http.post('/api/v1/login/', this.user)
      .subscribe(resp => {

          //Your logic

      }, err => {

         //Your logic

      }
  }
}

我们需要把它包含在 app.module.ts 文件中吗?如果需要,应该如何操作? - Rajeshwar
是的,您需要将其包含在 app.module.ts 中。 - Sanjay Achar
我已经创建了一个更好的,请在这里查看 - https://gist.github.com/iSanjayAchar/4ddd336b42d40066ee4e4f92acbfaef2 - Sanjay Achar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接