【问题标题】:Subscribing to observable of 2 types on Angular在 Angular 上订阅 2 种类型的 observable
【发布时间】:2020-07-12 12:16:15
【问题描述】:

很抱歉标题,但我找不到更好的。

我正在调用一个 HTTP API,它在发送 GET 命令时返回一个 json 对象,但如果找不到资源,它将返回 404。 我正在使用 Angular 9,我正在尝试找到一种方法从服务中输出 json 对象,或者在同一个 Observable 上返回接收到的 HTTP 错误的枚举值。

请看下面的代码:

device.service.ts

getDevice(objectID: number | string): Observable<Device | ResponseStatus> {
    return this.http.get<Device>(`http://localhost:8080/Registration/Device/${objectID}`)
      .pipe(
        catchError(this.handleError)
      );
  }
handleError(error: HttpErrorResponse): Observable<ResponseStatus> {
    switch (error.status) {
      case 404: {
        return of(ResponseStatus.objectNotFound);
        break;
      }
      case 409: {
        return of(ResponseStatus.objectAlreadyExists);
        break;
      }
    }
  }

我希望将 ResponseStatus 返回给我的组件,这样我就可以以相同的方式处理所有错误。

device-item-resolver-service.ts

export class DeviceItemResolverService implements Resolve<Device> {

  constructor(private ds: DeviceService, private router: Router) { }
  
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Device> | Observable<never> {

    let objectID = route.paramMap.get('objectID');

    return this.ds.getDevice(objectID).pipe(
      take(1),
      mergeMap(
        (item: Device) => {
          if (item) {
            return of(item);
          }
          else {
            this.router.navigate(['/devices']);
            return EMPTY;
          }
        }
      )
    );
  }
}

显然一切都很顺利。运行程序我可以接收设备,但我找不到在解析器上处理 ResponseStatus 的方法。

拜托,你能帮帮我吗?

【问题讨论】:

    标签: angular typescript http rxjs angular-observable


    【解决方案1】:

    不需要使用mergeMap,因为在这种情况下map 应该足够好了。

    import { map } from 'rxjs/operators';
    ....
    return this.ds.getDevice(objectID).pipe(
          take(1),
          map(
            (item: Device | ResponseStatus) => {
              // this if statement I think is the culprit.
              // Basically ResponseStatus.objectNotFound is true and it goes here
              // I am not sure if instanceof will work but basically you have to find out 
              // if you're getting Device or ResponseStatus and act accordingly
              if (item instanceof Device) {
                return item;
              }
              else {
                this.router.navigate(['/devices']);
                return null;
              }
            }
          )
        );
    

    【讨论】:

      【解决方案2】:

      我无法按照建议使用typeof 或instanceof,所以我找到了一篇关于打字稿中高级类型的精彩文档,如下: https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards

      请看下面我是如何解决这个问题的:

      首先我定义了一个用户定义的类型保护:

      function isDevice(value: Device | ResponseStatus): value is Device {
            return (value as Device).objectID !== undefined;
          }
      

      然后我在我的原始代码上调用了这个函数:

      return this.ds.getDevice(objectID).pipe(
            take(1),
            mergeMap(
              (item: Device | ResponseStatus) => {
                if (!item) {
                  this.router.navigate(['/devices']);
                  return EMPTY;
                }
                else if (isDevice(item)) {
                  return of(item)
                }
                else {
                  switch (item as ResponseStatus) {
                    case ResponseStatus.objectNotFound: {
                      this.router.navigate(['/devices']);
                      return EMPTY;
                    }
                  }
                }
              }
            )
          )        
        }
      

      请注意,我需要使用mergeMap。 map 没用。

      【讨论】:

        猜你喜欢
        • 2018-02-01
        • 2019-08-05
        • 2017-05-06
        • 2016-10-28
        • 2017-10-18
        • 2017-06-09
        • 2016-05-05
        • 2017-03-24
        • 1970-01-01
        相关资源
        最近更新 更多