Messenger app with Firebase - scrolling down whenever a new message is received

Hi, i found several threads regarding this topic but I wasnt able to make any of the solutions there work in my case. You will notice reading this, that I just started doing stuff with the ionic framework and i am not familiar with most of its syntax etc.

Im trying to build a messanger with ionic 6.13.1 and firebase firecloud using angular/fire

sending and receiving messages worked just fine but as soon as there are to many messages to show them all, my ion-content block reloads after receiving/sending another message and shows the first message in time instead of scrolling down to the last message sent what would be an users expected behavior.

Here is some of my code so you can get an idead of what im currently doing:
my ChatService (return value will be saved in messages$ Observable onInit of the page)

...
  getChatMessages() {
    return this.afs.collection<any>( "messages" , ref => ref.orderBy('createdAt')).valueChanges ();
  }
...

my html file

...
  <ion-grid>
    <ion-row *ngFor="let message of messages$ | async; last as last">
      <ion-col size="9" class="message"
        [offset]="(message.from === name) ? 3 : 0"
        [ngClass]="{ 'my-message': (message.from === name), 'other-message': !(message.from === name)}">
        <b>{{ message.from }}</b><br>
        <span>{{ message.msg }}
        </span>
        <div class="time ion-text-right"><br>{{ message.createdAt?.toMillis() | date:'short' }}</div>
      </ion-col>
      <ng-container *ngIf="last">{{adjustScrolling()}}</ng-container>
    </ion-row>
  </ion-grid>
...

my corresponding ts file

  adjustScrolling(){
    console.log("scrollingTriggered")
    this.content.scrollToBottom();
  }
...

The problem in my current solution seems to be that the grid isnt rendered when adjustScrolling gets called, but i have no clue how to access the point in time when ion-content finished rendering.

On a further note i observed, that in my presented solution adjustScrolling will be called multiple times (up to around 20) whenever i send a new message what doesnt really make any sense to me.

Id really apreciate any help.

Hi, your current structure is not very healthy. When there are too many messages, take all messages as they are will both tire the device and increase costs. Below is an example that I think is more accurate. When you apply this structure, your problem will be solved.

1 Like

Thanks a lot. Your stucture looks promising, I will try to adjust my code tomorrow, so I can tell you if it solved the problem. My only concern is that the app may feel a bit clunky to use if there is a 200ms scroll to Bottom delay whenever a new msg is received, but I guess i can test some smaller values as well. There is no way to trigger a function whenever my UI element thats connected to the message array finished rendering, and therefore i cant get rid of using a delay, right?

Actually, there is no logical delay. 200ms scroll speed. As a new message arrives, it will scroll without delay. You can set the ms value to 0.

True, my bad, I mistook it for
setTimeout(() => this.content.scrollToBottom(), 20);

I applied your suggestions to my code and ran in a problem I had severlal times now. Even with your stucture the scrolling doesnt work reliable. It does scroll, but in 4 out of 5 cases my app will scroll to the second last message instead of the last one. Feels a bit like a race between the scolling function and the rendering of the new message. By adding

setTimeout(() => this.content.scrollToBottom(), 20);

i can bypass this issue, but like I mentioned in the last post, the app might feel clunky to use then.

Did you try your code and is it working for you? Maybe I did something wrong in my html then?

Thanks for taking your time, like I said im a real ionic/typecipt noob/beginner :confused:
Lars

I guess the problem is the scroll function is triggered before the html occurs. A little screen recording would be nice to understand the for problem.

There you go:

There are two tings that are kinda odd.

The first one is that grid most of the times scrolls to the second last message.
The second one ist that im working with

firebase.firestore.FieldValue.serverTimestamp()

to get the point in time a sent message reaches the server. The messages in my firebase are timestamped, but the timestamp is only shown when i reload the page.
I noticed that messages coming from yourself and not from another user of you app, firebase observables will trigger twice when i use the firebase timestamp. When it triggers the first time, the createdAt Attribute of the new message I sent is null, so I think ionice might be aware of the fact im listening to the messages collection and the data take a shortcut or sth. Immediatly after this first time the observable will be triggered again cause it received the timestamp now from the firebase server and adds it to the message so my data collection changed again.

Im pretty sure my grammar is a mess here, I hope you get what im trying to say :´D

Unfortunately I do not have such a problem. Maybe you can revise the code as follows. This will not make the application look cumbersome. Most of the time this solution works for me.

setTimeout(() => this.content.scrollToBottom());

And also can I see the html file?

of course:

...
<ion-content class="ion-padding">
  <ion-grid>
    <ion-row *ngFor="let message of messages">
      <ion-col size="9" class="message"
        [offset]="message.myMsg ? 3 : 0"
        [ngClass]="{ 'my-message': message.myMsg, 'other-message': !message.myMsg }">
        <b>{{ message.from}}</b><br>
        <span>{{ message.msg }}
        </span>
        <div class="time ion-text-right"><br>{{ message.createdAt?.toMillis() | date:'short' }}</div>
      </ion-col>
    </ion-row>
  </ion-grid>
</ion-content>
...

myMsg is a boolean thats true if im the author of a msg

Maybe it’s due to the html tags used? I’ve created custom div tags for message boxes.

Using custom div´s didnt change anything in my case, but i might test the influence of the html components regarding the likelyhood of my scrolling to work in more detail in the next days.

Since you solved my initial problem and your approach to the messaging system is more efficient/stable/state of the art then my initial approach ill mark your answer as the solution.

If someone scrolls throught this thread and encounters similar problems i did, my two workarounds for the discribed issues are currently setting a 20ms Timeout until scrolling as well as checking in my message collection subscription if the timestamp is not null until displaying a message.

Thanks again mate for helping me out, I think my current code is good enought for its use case.

1 Like