3

Currently, I am calling the database to extract all the conversations of a specific user. After that, I am looping through those conversations and I extract metadata such as message text, message sender and etc from each conversation. I create an object for each with its' metadata which then are all stored in an Array - in my case this.recentChats.

this.af.getObservable(`userChats/${this.userID}/`).pipe(
  // we map the array of conversations to an array of the (before inner) observables

  map(recentConversations =>
    recentConversations.map(conversation =>
      this.af.getObservableSortByVar(`allChats/${conversation.conversationID}/`, 'lastUpdate'))),

  // combine the observables. will emit a new value of ALL conversation data when one of the conversations changes

  switchMap(recentConversations => combineLatest(recentConversations)),
  // map each conversation to the conversation object 
  map(conversations =>
    conversations.map(conversationData => {
      let userKey, lastMessage, lastMessageText, lastMessageSender, lastMessageDate;

      for (let i = 0; conversationData.length > i; i++) {
        switch (conversationData[i].key) {
          case 'messages': {
            lastMessage = (conversationData[i][Object.keys(conversationData[i])[Object.keys(conversationData[i]).length - 1]]);
            lastMessageText = lastMessage.message;
            lastMessageSender = lastMessage.sender;
            lastMessageDate = lastMessage.date;
          }
          case 'users': {
            userKey = conversationData[i].userKey;
          }
        }
      }
      return this.createConversationObject('username', userKey, lastMessageSender, lastMessageText, lastMessageDate);
    }))
).subscribe(recentChats => this.recentChats = recentChats);

However, on the line where return this.createConversationObject('username', ...) is called, I have been struggling to assign a user's actual username, fetched from the database.

Basically, I am using the userKey local variable, which is obtained from the switch-case code above, in order to attempt to do the following:

let tempUsername;
this.af.getUserName(userKey).then((username) => {
   tempUsername = username;
}

And then pass the tempUsername in the return statement. However, I have been struggling with making the result would to be awaited - in order for the username to be fetched, before the return is called.

Does anyone have any suggestions how can I properly achieve the desired result?

1
  • is this.af.getObservableSortByVar() returning an Observable as well? Commented Jul 18, 2018 at 6:08

1 Answer 1

1

Edit (after understanding the issue more closely)

Here's the code example for the proposed solution: Code example

Here are the modification that needs to be done to your code:

  • In the map(conversations => block, return the modified object with userkey appended and not the results of this.createConversationObject()

  • introduce switchMap after this and convert the Promise to Observable using rxjs -> from operator, also convert the results of the updated object returned from the previous map operation into a new Observable using rxjs -> of operators

  • now return the result of CombineLatest(OriginalObservable, fromPromiseObservable)

  • lastly you further need to map the results of these two Observable returns into one of use it directly in your call to this.createConversationObject()

  • and finally you can subscribe to the result to get the actual result as a final step

Hope this clarifies!

Original response

Here's my suggestion:

  • You could convert this.af.getUserName(userKey) promise to an observable first by using fromPromise provided by rxjs.
  • and then use this converted observable for username in your existing CombineLatest in the SwitchMap block
  • and finally use the result which would now be conversions and username in your map block to fetch the username for your return statement
Sign up to request clarification or add additional context in comments.

6 Comments

However, the userKey local variable is defined in the map(conversations => block. So basically, I cannot actually use it before it. Do you have any suggestions on how I can deal with that?
just to understand it more clearly: in your map(conversations => block, you fetch userkey with the switch -> case. And have this promise code to get user from userkey inside the createConversationObject(..) method?
correct! After fetching the userKey, I want to use it in the promise in order to make a new call to the database and retrieve the user's name. After retrieving the name, I want to then pass it to createConversationObject(..).
cool. so essentially you should do is not call createConversationObject in the map(conversations => block since your createConversationObject would be last step in the chain; you should do that at the end. But first you should return the mapped data with the userkey. Introduce another map block after your existing one and add your promise block converted to an observable returned. You may need to add a filter after this in your chain to call createConversationObject only when you have the username returned by the promise.
no issues, give me some time, I will probably edit my above answer as per the discussion we had.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.