Alexandru Tuca
Alexandru Tuca

Reputation: 186

How to access arguments from previous observables when using pipe in rxjs 6?

I am currently migrating from rxjs 5 to 6, and I cannot figure out how to access an argument from a previous Observable. I was using the following code in rxjs 5:

return this.userProvider.getCurrentUser().concatMap(currentUser => {
      return this.db.collection('chats').doc(room).collection<MessageModel>('messages', ref => ref.limit(25).orderBy("date", "desc")).stateChanges(["added"])
        .map(docChange => docChange.map(doc => {
          const message = doc.payload.doc.data() as MessageModel;
          message.sender = (message.senderId === currentUser.userId) ? currentUser : receiver;
          return message;
        }).reverse());
    });

I have converted the code to rxjs 6 (using pipe) as follows:

return this.userProvider.getCurrentUser().pipe(
      concatMap(currentUser => {
        return this.db.collection('chats').doc(room)
        .collection<MessageModel>('messages', ref => ref.limit(25).orderBy('date', 'desc')).stateChanges(['added']);
      }),
      map(docChange => docChange.map(doc => {
        const message = doc.payload.doc.data() as MessageModel;
        message.sender = (message.senderId === currentUser.userId) ? currentUser : receiver;
        return message;
      }).reverse())
    );

In this way, however, I cannot access currentUser, since it is only accessible in the scope of concatMap. How would I be able to refactor the code in order to access currentUser? Thank you.

Upvotes: 1

Views: 1329

Answers (2)

Picci
Picci

Reputation: 17762

It seems that in your original RxJs 5.x code you were applying the logic .map(docChange => .... to the result of this.db.collection('chats').doc(room).collection<MessageModel>(....), result which likely to be an Observable which emits an Array-like of MessageModel(s,

If all this is true, then you may consider an approach which is close to your RxJs code along the following lines

return this.userProvider.getCurrentUser().pipe(
  concatMap(currentUser => 
    this.db.collection('chats').doc(room).collection<MessageModel>('messages', ref => ref.limit(25).orderBy('date', 'desc')).stateChanges(['added'])
    .pipe(
        map(
          docChange => docChange.map(doc => {
             const message = doc.payload.doc.data() as MessageModel;
             message.sender = (message.senderId === currentUser.userId) ? currentUser : receiver;
             return message;
          }).reverse()
        )
    )
  )
);

Here we pipe the map operator directly into the result of the db.collection query, so that we have immediately in scope the currentUser.

I am not able to reproduce the case, so this is a bit of speculation and the approach has to be validated. I hope anyways you grasp the idea behind it.

Upvotes: 0

Fan Cheung
Fan Cheung

Reputation: 11345

You can pass current user along with another pipe and map

return this.userProvider.getCurrentUser().pipe(
      concatMap(currentUser => 
       this.db.collection('chats').doc(room)
        .collection<MessageModel>('messages', ref => ref.limit(25).orderBy('date', 'desc')).stateChanges(['added'])
        .pipe(map(docChange)=>({currentUser,docChange}))
      ),
      map(({currentUser,docChange}) => docChange.map(doc => {
        const message = doc.payload.doc.data() as MessageModel;
        message.sender = (message.senderId === currentUser.userId) ? currentUser : receiver;
        return message;
      }).reverse())
    );

Upvotes: 3

Related Questions