简体   繁体   English

在另一个可观察对象中使用数据,然后将结果作为其他可观察对象返回

[英]Use data from one observable in another and then return result as other observable

I am solving this issue:我正在解决这个问题:

The application flow:申请流程:

I have to call the first API endpoint (let's call it EP-A for simplicity) which takes Blob as body and fileType as a request parameter.我必须调用第一个 API 端点(为简单起见,我们称它为 EP-A),它将 Blob 作为正文,将 fileType 作为请求参数。 Its performed via calling automatically generated class它通过调用自动生成的 class 来执行

  uploadFile$Response(params?: {
    fileType?: 'USER_AVATAR' | 'UNKNOWN' | 'DELIVERY_LOGO' | 'PAYMENT_LOGO' | 'ITEM_PICTURE';
    body?: { 'file'?: Blob }
  }): Observable<StrictHttpResponse<FileUploadResponse>> {

    const rb = new RequestBuilder(this.rootUrl, FileControllerService.UploadFilePath, 'post');
    if (params) {
      rb.query('fileType', params.fileType, {});
      rb.body(params.body, 'application/json');
    }

    return this.http.request(rb.build({
      responseType: 'blob',
      accept: '*/*'
    })).pipe(
      filter((r: any) => r instanceof HttpResponse),
      map((r: HttpResponse<any>) => {
        return r as StrictHttpResponse<FileUploadResponse>;
      })
    );
  }

The StrictHttpResponse<T> is simply an interface holding a "generic" body (so you can retrieve data that will have a structure defined by swagger from which this method is generated). StrictHttpResponse<T>只是一个包含“通用”主体的接口(因此您可以检索具有由 swagger 定义的结构的数据,从该结构生成此方法)。

Then the result FileUploadResponse which is an object like然后是 object 的结果FileUploadResponse

{
 uuid: string,
 time: Timestamp

 ...
 Other members omitted for simplicity
 ...
}

is sent to another EP (let's call it EP-B ) right after EP-A call returns a value, EP-B takes an object below as a body and currently logged person as a path variable.EP-A调用返回一个值之后立即发送到另一个 EP(我们称之为EP-B ), EP-B将下面的 object 作为主体,并将当前记录的人员作为路径变量。

{
 uuid: string
}

So before calling EP-B the result from EP-A should be parsed (in this case, the uuid field should be taken and put into a new object for EP-B calling)因此,在调用 EP-B 之前,应解析来自 EP-A 的结果(在这种情况下,应获取 uuid 字段并将其放入新的 object 以进行 EP-B 调用)

Again via the generated method with a similar signature as the one above (and I will omit it for simplicity).再次通过具有与上述签名类似的签名的生成方法(为简单起见,我将省略它)。

If everything performed well, I´d like to let the caller know about that.如果一切正常,我想让来电者知道这一点。 If anything failed (any of these 2 EP calls), I´d like to let it know to call of this method to react somehow (show alert, change page somehow, ...)如果有任何失败(这两个 EP 调用中的任何一个),我想让它知道调用此方法以做出某种反应(显示警报,以某种方式更改页面,...)

The method I have is now incomplete, I do not know how to "connect" these 2 Observables, I´ve read about mergeMap, flatMap, etc. but I am not sure how to use it in my case.我现在使用的方法不完整,我不知道如何“连接”这两个 Observable,我已经阅读了有关 mergeMap、flatMap 等的信息,但我不确定如何在我的情况下使用它。

  updateUserAvatar(avatar: Blob): Observable<boolean> {

    return new Observable<boolean>((observer) => {

      // Calling EP-A
      this.avatarFormChangeRequestSubscription = this.fileControllerService.uploadFile$Response({
        fileType: 'USER_AVATAR',
        body: {
          file: avatar
        }
      })
        .subscribe((response: StrictHttpResponse<FileUploadResponse>) => {
            // Handle returned UUID and somehow pass it into an observable belog
            console.log(response);
          },
          (error: any) => {
            observer.error(error);
          });

      // Creating object for EP-B calling
      const avatarUpdateParams = {
        id: 1, // Just dummy ID for now, will be dynamically changed
        body: {
          avatarUUID: '' // the UUID from observable response above should be placed here
        }
      };

      // Calling EP-B
      this.avatarFormChangeRequestSubscription = this.userControllerService.updateUserAvatar$Response(avatarUpdateParams)
        .subscribe((response: StrictHttpResponse<string>) => {
          // Handle successfull avatar upload (change the "Logged user" object avatar to change it everywhere etc
          console.log(response);
          observer.next(true);
        },
          (error: any) => {
            observer.error(error);
          });
    });
  }

At the end I would like to add "use case" flow too to understand what I am trying to achieve from user view:最后,我还想添加“用例”流程,以了解我要从用户视图中实现的目标:

User uploads his photo which is firstly uploaded into a file system (and linked with database record) on BE side, then this file is linked to his profile as his profile picture.用户上传他的照片,该照片首先上传到BE端的文件系统(并与数据库记录链接),然后将该文件链接到他的个人资料作为他的个人资料图片。

You could do it using rxjs .您可以使用rxjs来做到这一点。 Something like that might works:类似的东西可能有效:

this.fileControllerService.uploadFile$Response({
    fileType: 'USER_AVATAR',
    body: {
      file: avatar,
    },
  })
  .pipe(
    tap((responseOfFirstApiCall: StrictHttpResponse<FileUploadResponse>) => {
      // Do whatever you want here, but you might not need that since you get the response below as well (in the flatMap)
      // Handle returned UUID and somehow pass it into an observable belog
      console.log(response);
    }),
    flatMap(
      (responseOfFirstApiCall: StrictHttpResponse<FileUploadResponse>) => {
        // Creating object for EP-B calling
        const avatarUpdateParams = {
          id: 1, // Just dummy ID for now, will be dynamically changed
          body: {
            avatarUUID: '', // the UUID from observable response above should be placed here
          },
        };

        return this.userControllerService.updateUserAvatar$Response(avatarUpdateParams);
      }
    ),
    tap((responseOfTheSecondApiCall: StrictHttpResponse<string>) => {
      // Handle successfull avatar upload (change the "Logged user" object avatar to change it everywhere etc
      console.log(response);
      observer.next(true);
    }),
    catchError((err: any) => of(err))
  )
  .subscribe(); // Empty subscribe() call to trigger the http request. Not needed if you get the result somewhere else (eg if your method return an observable that you want to handle the result somewhere else)

flatMap() is the same as mergeMap. flatMap()与 mergeMap 相同。 Change it as you wish, there's a lot of option like map or switchMap that you should learn about since they are useful.根据需要更改它,有很多选项,例如mapswitchMap ,您应该了解它们,因为它们很有用。

Basically, the pipe allow you to chain functions, and if there is an error, then the catchError is triggered.基本上, pipe允许您链接函数,如果有错误,则触发catchError

Tip: Note that what is in the pipe is executed BEFORE the result of your api call.提示:请注意,在pipe调用的结果之前执行 pipe 中的内容。 So if you want to do something with your result before to get it, then think about rxjs :因此,如果您想在获得结果之前对结果做一些事情,那么请考虑rxjs

service服务

getUser(id: string) {
  return this._http.get<any>(url).pipe(
    map(result => result.email), // Return only the email
  );
}

component:零件:

  ngUnsubscribe = new Subject();

  ngOnInit() {
    this._userService.getUser(1)
    .pipe(takeUntil(this.ngUnsubscribe)) // Don't forget to unsubscribe !
    .subscribe(email => console.log('email = ', email))
  }

  ngOnDestroy() {
    this.ngUnsubscribe.unsubscribe();
    // or
    // this.ngUnsubscribe.next();
    // this.ngUnsubscribe.complete();
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM