简体   繁体   English

如何链接 rxjs observables 以获取内部 observable 的值并在 Angular 中与父级一起返回

[英]How to chain rxjs observables to get value of inner observable and return with parent in Angular

I make a request to firestore to get a user's chats and it returns an observable array of objects with this shape我向 firestore 发出请求以获取用户的聊天记录,并返回具有此形状的可观察对象数组

[...,
  {
     key: '83hed87djhe09',
     participants: ['owner_43', 'visitor_69']
  },
...]

This displays a list of all user's chats in the UI, however I'd like to search for chats by user name.这会在 UI 中显示所有用户聊天的列表,但是我想按用户名搜索聊天。 In order to do that, I'd have to make a http request to a backend server for the user name of each participant and replace that in the participants thread to make it searchable on type.为了做到这一点,我必须向后端服务器发出一个 http 请求以获取每个参与者的用户名,并在参与者线程中替换它以使其可按类型搜索。

So 'owner_43' would become 'John Doe' for example.例如,'owner_43' 将变成 'John Doe'。

Problem I'm experiencing is that I get an array of observables for the participant names rather than an array of strings.我遇到的问题是,我得到了参与者姓名的一组可观察值,而不是一组字符串。

在此处输入图片说明

Here's my code这是我的代码

this.chat$ = this.chatSvc.getUserChats(this.userUID).pipe(
  map((chats: any) => {
    return chats.map((chat: any) => {
      return {
        key: chat.key,
        participants: chat.participants.map((participant: any) => {
          return this.userSvc.getUserFromString(participant);
        })
      }
    })
  })
);

Here's the getUserFromString function:这是 getUserFromString 函数:

getUserFromString(stringId){

  let splitValue = stringId.split("_");
  let accountType = splitValue[0];
  let id = splitValue[1];

  if (accountType === 'owner') {
    return this.ownerSvc.getOwner(id);
  }
  else if (accountType === 'visitor') {
    return this.visitorSvc.getVisitor(id);
  }
}

Get owner function simply returns:获取所有者函数简单地返回:

return this.http.get(owner_url + id);

Finally the result is unwrapped in the view using the angular async pipe最后使用角度异步管道在视图中展开结果

<ul><li *ngFor="let msg of chat$|async">{{msg.key}}</li></ul>

What am I doing wrong?我究竟做错了什么?

Assuming your Chat looks like this:假设您的Chat如下所示:

/**
 * Type parameter is being used
 * due to participants initially being of type string[]
 * and ultimately of type User[]
 */
class Chat<T> {
  key: string;
  participants: T[]
}

Consider the following implementation:考虑以下实现:

this.chat$: Observable<Chat<User>[]> = this.chatSvc.getUserChats(this.userUID).pipe(
  mergeAll(),
  mergeMap(({ key, participants }: Chat<string>) => {
    return forkJoin(participants.map(this.userSvc.getUserFromString)).pipe(
      map(participants => ({ key, participants }))
    )
  }),
  toArray()
)

Explanation (Simplified):说明(简体):

this.chat$ = this.chatSvc.getUserChats(this.userUID).pipe(

/**
 * flattens Observable<Chat[]> into a stream
 * of Observable<Chat> so we can handle single Chat at a time
 */
  mergeAll(), 

 /**
  *  transform each Chat into an 
  *  Observable containing a new value
  */
  mergeMap(({ key, participants }: Chat) => {

   /**
    * transform participants (String[]) into an array of Observables 
    * (Observable<User>[])
    */
    const participants$ = participants.map(this.userSvc.getUserFromString)
    
   /**
    *  wait for all Observables to complete using forkJoin
    *  then return new Chat using map
    */
    return forkJoin(participants).pipe(
      map(participants => ({ key: key, participants: participants  }))
    )
  }),
  toArray() // <= transform stream back into array (Observable<Chat[]>)
)

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

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