首页 > 解决方案 > 将 LoadingController 包裹在可观察对象周围

问题描述

我用 Angular7/Ionic4 重建的旧应用程序有问题。

我正在尝试使用 LoadingController 在调用远程服务时显示指示器,但我遇到了一些麻烦。

我现在的情况如下。我有PageComponent一个简单的加载方法,例如:

export class PageComponent {

  constructor(private itemsService: ItemsService) { }

  fillData() {
    this.itemsService.getItems().subscribe(items => {
      this.items = items;
    });
  }

}

ItemsService也很简单:

export class ItemsService {

  constructor(private http: HttpClient) { }

  getItems() {
    let url = 'http://example.org/items/endpoint';

    return this.http.get(url).pipe(
      map(this.buildItems.bind(this)
    );
  }

  private buildItems(items: any[]) {
    // convert remote data format to internal one
  }
}

现在我想在LoadingController两者之间放置一个,让调用者和被调用者基本上都不知道真正发生了什么。

所以我的想法是创建一个从页面类调用的中间服务类。为了使其足够灵活以用于任何类型的服务(我有多个ItemsService),我尝试传递给中间类 ,就像Observable我从这样的类中得到的ItemsService一样:

(在PageComponent

fillData() {
  this.loadingService.loadData(this.itemsService.getItems()).subscribe(items => {
    this.items = items;
  });
}

我定义了一个这样的新服务:

export class LoadingService {

  loadData(observable: Observable<any>): Observable<any> {
    return observable.pipe(
      finalize(() => {
        console.log('after data received');
      })
    );
  }

}

这段代码似乎有效。当我调用fillDatain 时PageComponent,我从 中获取 observable ItemsService,向其中添加一个finalize()运算符,最后 (in fillData()) 我订阅了 observable,调用了真正的远程请求。

这样,如果我有很多形状像 的服务ItemsService,我可以做

this.loadingService.loadData(this.service1.getData()).subscribe( /* ... */ );
this.loadingService.loadData(this.service2.getData()).subscribe( /* ... */ );
this.loadingService.loadData(this.service3.getData()).subscribe( /* ... */ );
/* ... and so on */

但是,一旦我添加了LoadingControllerin LoadingService,事情就变得很奇怪。这就是我更改服务的方式:

export class LoadingService {
  private loader = null;

  constructor(private loadingController: LoadingController) { }

  loadData(observable: Observable<any>): Observable<any> {
    this.openLoader();
    return observable.pipe(
      finalize(() => {
        this.closeLoader();
      })
    );
  }

  private async openLoader() {
    if (! this.loader) {
        this.loader = await.loadingController.create();
    }
    await this.loader.present();
  }

  private async closeLoader() {
    if (this.loader) {
      await this.loader.dismiss();
      this.loader = null;
    }
  }
}

现在我得到的是加载控制器实际上显示了指示器,并且在远程调用结束后通常不会关闭它。但是,有时我会得到正确的行为:指示器显示,呼叫开始,呼叫结束,指示器消失。

我对 JS 中基于事件的编程不是很有信心,所以这可能是一个非常愚蠢的问题,但我需要一些帮助来解决这个问题。

非常感谢,

马可

标签: angularionic-frameworkionic4

解决方案


我在几个按预期工作的应用程序中使用了以下加载程序服务。

装载机服务

private loader;
constructor(private loaderCtrl: LoadingController) {
  this.loader = null;
}

async show(message?: string) {
  if (this.loader !== null) {
    this.loader.dismiss();
    this.loader = null;
  }

  this.loader = await this.loaderCtrl.create({
    spinner: 'crescent',
    message: message ? message : 'Please wait...',
  });
  return this.loader.present();
}

hide() {
  if (this.loader !== null) {
    this.loader.dismiss();
    this.loader = null;
  }
}

这是调用 API 的脚本 -

组件 ts

try {
  await this.loaderSvc.show();
  this.service1.getData().subscribe((res) => {
  }, err => {
    throw "Error calling API";
  });
} catch (error) {
  console.log(error);
} finally {
  this.loaderSvc.hide();
}

推荐阅读