Ionic 3 Angular 5 如何在 ngOnInit 中获取数据并将其转换为 Observable

Ionic 3 Angular 5 How fetch data and transform it to Observable in ngOnInit

你好,我需要从 API 获取数据,然后根据响应 return Observable in ngOnInit.

@Edit 基本上 this.dayOverViewByGroup 应该从 api 完全下载 return 在 fetchChildrensData() => return Observable.of(this.dayOverViewByGroup).

中编辑时

@Edit2 添加了 getDayOverViewByGroupId

的代码

ngOnInit


ngOnInit() {
    const filter$: Observable<string> = this.filterControl.valueChanges.pipe(
      startWith(''),
      debounceTime(100), 
      distinctUntilChanged(),
      share()
    );
    this.dayOverViewByGroup$ = this.fetchChildrensData().pipe(
      map(days => days.map(day => (
        {
          ...day,
          filteredChildren$: filter$.pipe(this.filterFrom(day.children))
        }
      )))
    );
  }

fetchChildrensData 函数

 fetchChildrensData(): Observable<any[]> {
    return Observable.of(this.dayOverViewByGroup)
 }

处理API调用的函数

getChildrens(date, groupId) {
    return this.attendanceService.getDayOverViewByGroupId(date, groupId).then(
      (res1: any) => {
        let dayOverViewByGroup = res1.mobile_employee_dayoverview;
        this.dayOverViewByGroup = dayOverViewByGroup;
        this.appFunctionCtrl.dismissLoader();  
      },
      (error) => console.log('Error occured in this.attendanceService.getDayOverViewByGroupId()', error)
    );

  }
getDayOverViewByGroupId(currentDate = null, groupId) {
    let that = this;
    return new Promise((resolve, reject) => {
      that.wsseGenerator.getWSSEHeader().then(header => {
        header.append('Access-Control-Allow-Origin', '*');
        header.append('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT');
        let options = new RequestOptions({ headers: header });
        let paramsData = {
          groupId: groupId,
          currentDate: currentDate
        };
        let params = that.serializeObject(paramsData);
        that.http.post(`${that.baseUrl}/dayoverview?${params}`, null, options).timeout(this.timeTimeout).subscribe((success: any) => {
          resolve(success);
        }, (err) => {

          this.appFunctionCtrl.dismissLoader();
          if (err.name == 'TimeoutError') {
            this.alert.present();
          }
          else {
            reject(err);
          }
        });
      });
    });
  }

你应该 return 从你的服务中得到一个不会抛出任何错误的 Observable,这样你就可以直接在你的组件中使用 AsyncPipe 来订阅(另见:)。

将无法更改的 Api 调用和 return Promises 转换为 from 的 Observables,并从那时起使用 RxJS 运算符(我假设 this.wsseGenerator.getWSSEHeader()是这样的称呼)。

使用switchMap映射到不同的Observable,pluckmap提取/转换returned数据,catchError做事情错误和 return 不抛出任何错误的 Observable,finalize 在 Observable 错误或完成时执行操作。

在您的服务中:

import { Observable } from "rxjs";
import { switchMap, map, timeout, catchError, finalize } from "rxjs/operators";

getDayOverViewByGroupId(currentDate = null, groupId): Observable<any> {
  return Observable.from(this.wsseGenerator.getWSSEHeader()).pipe( // use from to convert Promise to Observable
    switchMap(header => {
      header.append('Access-Control-Allow-Origin', '*');
      header.append('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT');
      let options = new RequestOptions({ headers: header });
      let paramsData = {
        groupId: groupId,
        currentDate: currentDate
      };
      let params = that.serializeObject(paramsData);
      // map to your http request
      return this.http.post(`${that.baseUrl}/dayoverview?${params}`, null, options);
    }),
    map(this.getRelevantData), // get relevant data from http response
    timeout(this.timeTimeout),
    catchError(error => { // handle errors and return an Observable that doesn't error
      console.log('Error occured in this.attendanceService.getDayOverViewByGroupId()', error);
      if (error.name == 'TimeoutError') {
          this.alert.present();
      }
      // you have to think about what default value you want to return on errors, null can be ok
      return Observable.of(null); 
    }),
    finalize(() => this.appFunctionCtrl.dismissLoader()) // do stuff on error and complete
  );
}

private getRelevantData(response): any { // <-- don't return 'any' in your real code, create interfaces to type your data if you can
  let dayOverViewByGroup = response.mobile_employee_dayoverview;
  dayOverViewByGroup.forEach(element => {
    // do your thing
  }
  console.log('dayOverViewByGroup', dayOverViewByGroup)
  return dayOverViewByGroup;
}

在您的组件中:

ngOnInit() {
  this.dayOverViewByGroup$ = this.attendanceService.getDayOverViewByGroupId( .. ).pipe( 
    // If the Observable from your service can emit 'null' and you do
    // map(days => days.map(..)) you will get an error 
    // so you might have to handle this case here

    // 1. Option: filter out 'null' and 'undefined' values before your 'map' and don't emit anything
    filter(Boolean)

    // 2. Option: handle 'null' and 'undefined' in your map function
    map(days => {     
      if (days) {
        days.map( .. )
      } else {
        // do something else or don't do anything at all, i.e. remove the else case
      }
    })
  )
}