Mindless
Mindless

Reputation: 2357

Angular Firebase listen to foreach changes with subscribe

I am subscribing to get user chats and then for each chat, I am subscribing to two other observables.

get_user_chat(chat) {
    let user = this.firebase.get_user_by_uid(chat.key).snapshotChanges();
    let chatInfo = this.firebase.get_single_chat(chat.payload.val()).snapshotChanges();
    return Observable.forkJoin(user.take(1), chatInfo.take(1));
}

getChats() {
//start loading
let loading = this.loadingCtrl.create();
loading.present();

//get chats
this.firebase.get_user_chats().snapshotChanges().takeUntil(this.ngUnsubscribe).subscribe(chats => {
  chats.forEach(chat => {
    this.get_user_chat(chat).takeUntil(this.ngUnsubscribe).subscribe(userChat => {
      this.userChat = userChat;
      this.user = this.userChat[0];
      this.chat = this.userChat[1];

      this.chats.push({
        firstName: this.user.payload.val().firstName,
        imageUrl: this.user.payload.val().imageUrl,
        uid: this.user.key,
        chatId: chat.payload.val(),
        last_message: this.chat.payload.val().last_message.message,
        type: this.chat.payload.val().last_message.type
      })
    })
  })
  //dimiss loading
  loading.dismiss();
}, err => {
  //dimiss loading
  loading.dismiss();
})

}

Now for the front end, I am displaying the data like this:

<ion-content>
  <ion-list class="chat-list" *ngIf="(chats)?.length>0">
    <a ion-item detail-none *ngFor="let c of chats" (click)="toChat(c.chatId, c.uid)">
      <ion-thumbnail item-start>
        <img-loader class="img-logo" src={{c.imageUrl}} fallbackUrl="assets/img/placeholder-person.png" useImg></img-loader>
      </ion-thumbnail>
      <h2>{{c.firstName}}</h2>
      <h3 *ngIf="c.type!='img'">{{c.last_message}}</h3>
      <img class="img-placeholder" *ngIf="c.type=='img'" src="assets/img/placeholder-image.png">
      <!-- <ion-icon item-right name="ios-arrow-forward"></ion-icon> -->
    </a>
  </ion-list>
  <ion-card *ngIf="(chats)?.length==0">
    <ion-card-content>
      You don't have any chats.
    </ion-card-content>
  </ion-card>
</ion-content>

This is working except that chat last message won't update automatically in the front end, I understand why this isn't working, I am pushing the observer into an array which loses the function to listen to changes, but I couldn't figure out how I can listen to changes without pushing the objects from two different subscribers and display them correctly. I basically have to reload the chat list every time to see the change.

It's better explained with pictures:

Last message for Holly is 'a' Last message for Holly is a

I send another message to Holly, the last message should now be 'B' I send another message, the last message should now be B

But last message won't update without refreshing the page, it's not listening to changes because I am pushing the observable into an array But last message won't update without refreshing the page

Firebase realtime database structure for 1:1 chat

User 1: enter image description here

User 2: enter image description here

Chat Room: enter image description here

Upvotes: 0

Views: 1191

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

I highly recommend modeling each chat room as a collection in Firestore. That way, if you have a chat room/collection for the chat between Brendan and Holly, you're only reading from a single collection, instead of two. That also makes it much easier to keep the messages in the correct order, since you can use a single query to get them.

For an example of this see Best way to manage Chat channels in Firebase. While this question is about Realtime Database, the same logic can be applied to Cloud Firestore.

Upvotes: 1

Related Questions