[IONIC 4] Scroll to bottom on chat page

Hi there !

I’m creating an app which contains a chat functionality and I’m trying to implement the scrollToBottom() function when I reach my chat page and my messages are loaded.
Here’s what I’ve done so far:

<ion-content [scrollEvents]="true">
  <div class="messages-container" *ngIf="connectedUser">
    <ol class="messages">
      <li *ngFor="let msg of messages" [class.mine]="connectedUser.id === msg.userFrom.id">
        <span class="msg-content">{{msg.content}}</span>
      </li>
    </ol>
  </div>
</ion-content>
import {IonContent} from '@ionic/angular';
import {Component, OnInit, ViewChild} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {RestApiService} from '../services/rest-api.service';
import {AlertService} from '../services/alert.service';

export class ChatPage implements OnInit {
    @ViewChild(IonContent) content: IonContent;
    connectedUser = null;
    messages = [];
    contactId = null;

    constructor(private activatedRoute: ActivatedRoute, private api: RestApiService, private alert: AlertService) {
        this.contactId = this.activatedRoute.snapshot.paramMap.get('contactId');
    }

    ngOnInit() {
        this.getMessages();
    }

    getMessages() {
        this.api.get('conversation/getMessages/' + this.contactId).subscribe(res => {
            this.messages = res;
            setTimeout(() => {
                this.updateScroll();
            }, 500);
        }, err => {
            this.alert.present();
        });
    }

    updateScroll() {
        if (this.content.scrollToBottom) {
          this.content.scrollToBottom(400);
        }
    }
}

Unfortunately, it doesn’t scroll at all. I can log things in my updateScroll() function, so I reach this code, but it still doesn’t scroll.

Any ideas ?
Thanks.

3 Likes

you just need to define reference for component:
like this:

<ion-content #scrollElement padding>
</ion-content>
@ViewChild("scrollElement") content: IonContent;

i hope its work for you
:slight_smile:

1 Like

I tried that too but the result is just the same: no errors, I reach the scroll code, but It doesn’t scroll.
I don’t know what I’m missing here :confused:

try by removing delay from function and also a if condition.

1 Like

Without the if statement, I got this error:

ERROR TypeError: this.content.scrollToBottom is not a function

With this code I have the console.log() triggered and the above error.

  updateScroll() {
    console.log('scrolling');
    this.content.scrollToBottom();
  }

Do you think it has something to do with the IonContent element ?

ok first define and use reference as i suggested than remove if condition.

Yeah that’s what I did, let me show you:

<ion-content #scrollElement padding>
  <div class="messages-container" *ngIf="connectedUser">
    <ol class="messages">
      <li *ngFor="let msg of messages" [class.mine]="connectedUser.id === msg.userFrom.id">
        <span class="msg-content">{{msg.content}}</span>
      </li>
    </ol>
  </div>
</ion-content>

@ViewChild('scrollElement') content: IonContent;

updateScroll() {
  this.content.scrollToBottom();
}

The updateScroll() function is well called (I logged something before the scrollToBottom), I have no errors but it doesn’t scroll :confused:

1 Like

can you upload full code snippet?

Sure, HTML first and then TS file. Some text are French but don’t mind it :wink:

<ion-header>
  <ion-toolbar mode="ios">
    <ion-buttons slot="start">
      <ion-back-button [routerLink]="'/tabs/ma-messagerie'" defaultHref="ma-messagerie"></ion-back-button>
    </ion-buttons>
    <ion-title *ngIf="contact">{{contact.prenom}} {{contact.nom}}</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content #scrollElement padding [scrollEvents]="true">
  <div class="messages-container" *ngIf="connectedUser">
    <ol class="messages">
      <li *ngFor="let msg of messages" [class.mine]="connectedUser.id === msg.userFrom.id">
        <span class="msg-content">{{msg.content}}</span>
      </li>
    </ol>
  </div>
</ion-content>
<ion-footer>
  <ion-item>
    <ion-textarea
            rows="1"
            placeholder="Envoyer un message"
            maxlength="500"
            autocapitalize="on"
            autosize
            [(ngModel)]="newMessage"
    >
    </ion-textarea>
    <ion-buttons slot="end">
      <ion-button slot="icon-only" (click)="sendMessage()">
        <ion-icon name="send"></ion-icon>
      </ion-button>
    </ion-buttons>
  </ion-item>
</ion-footer>

import {Component, OnInit, ViewChild} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {RestApiService} from '../services/rest-api.service';
import {AlertService} from '../services/alert.service';
import {IonContent} from '@ionic/angular';

@Component({
  selector: 'app-chat',
  templateUrl: './chat.page.html',
  styleUrls: ['./chat.page.scss'],
})
export class ChatPage implements OnInit {
  contactId = null;
  contact = null;
  connectedUser = null;
  messages = [];
  newMessage: any = '';
  @ViewChild('scrollElement') content: IonContent;

  constructor(private activatedRoute: ActivatedRoute, private api: RestApiService, private alert: AlertService) {
    this.contactId = this.activatedRoute.snapshot.paramMap.get('contactId');
  }

  ngOnInit() {
    this.getContactInfos();
    this.getUser();
    this.getMessages();
  }

  getContactInfos() {
    this.api.get('user/getInfosUser/' + this.contactId).subscribe(res => {
      this.contact = res;
    }, err => {
      this.alert.present();
    });
  }

  getUser() {
    this.api.get('user/user').subscribe(res => {
      this.connectedUser = res;
    }, err => {
      this.alert.present();
    });
  }

  getMessages() {
    this.api.get('conversation/getMessages/' + this.contactId).subscribe(res => {
      this.messages = res;
      setTimeout(() => {
        this.updateScroll();
      }, 500);

    }, err => {
      this.alert.present();
    });
  }

  sendMessage() {
    const data = {
      contactId: this.contactId,
      content: this.newMessage
    };

    this.api.post('message/create', data).subscribe(res => {
      if (res['result'] === 'success') {
        this.newMessage = '';
        this.messages = [];
        this.ngOnInit();
      } else {
        this.alert.present('Echec lors de l\'envoi de votre message.');
      }
    }, err => {
      this.alert.present('Echec lors de l\'envoi de votre message.');
    });
  }

  updateScroll() {
    console.log('scrollToBottom');
    this.content.scrollToBottom();
  }

}

I also tried to do it in ionViewDidEnter instead of ngOnInit but the result is the same, no scrolling :confused:
I really don’t know what I’m missing, it shouldn’t be that hard after all :face_with_monocle:

EDIT: Even if I call updateScroll() when clicking on a button or when focusing my text input, it gets called (I logged it), but it doesn’t want to scroll to bottom.

Any ideas from anyone ? Struggling on this

I also needed to set programatically the scroll to the bottom in my app, after some trouble I got it working, I’ve seen your code and I’m not really sure what’s wrong/missing, I’ll share everything I’ve done to get it working, mby it could help you

in hml
<ion-content [scrollEvents]=“true”>

getting IonContent with:
import { IonContent } from ‘@ionic/angular’;

in ts
image

creating scroll effect with:
this.content.scrollToBottom(300);

ATTEMPT TO FIX 1 - Try to do it like me, dont ID your content to scrollElement and instead do it with the IonContent

ATTEMPT TO FIX 2 - Yknow, in my app I wanted to scroll to the bottom of the page when the user selected an input field on the login page, the input field happened to be inside an ion-item, and what that lead to was an odd bug, when I clicked on an input for the first time the keyboard opens and the click event isn’t triggered, only on the 2º click it got triggered, so clicking on the input once the keyboard is opened, awkward I know, so I rathered checking for another event, when the keyboard opens, because when he first clicks on the input the keyboard opens, so I managed to get a triggered event pretty much in the same context I needed, what do I mean with all this, maybe you’re not really ever running the scroll event? TL:DR: are you sure the scroll is being executed?

Hi guys !

I tried your fix 1 @SanduCuragau, but unfortunately, it doesn’t scroll.

<ion-content [scrollEvents]="true">
@ViewChild(IonContent) content: IonContent;
updateScroll() {
    console.log('should scroll here');
    this.content.scrollToBottom(300);
}

‘Should scroll here’ is logged, I can see it in the Chrome dev tools, but there’s still no scroll on my page.
Maybe I don’t call it at the right time, but even if I call it from a button click (when my messages are already on my chat page), it doesn’t scroll to the bottom…

For the 2nd attempt to fix, I see hat you’re talking about, but I don’t think this is it here, cause my console.log('should scroll here') is always executed when I need it. Problem is, it doesn’t scroll and I have no errors about it…

Hope we’ll make it !

Hm, try 1 thing, add like random buttons or whatever out of your screen and create a legit need to scroll through the whole page and try to execute updateScroll() cuz I think what’s happening here is that in my case I used it to scroll legit the page itself, I didn’t get to try to understand your code but I think you’re trying to scroll something else, just the chat, the page is never scrolled since there’s no need to scroll it since everything fits tight, if in my login page I have keyboard opened and it creates a need to scroll the page itself, if I execute the scroll it goes to the bottom, but when keyboard isn’t opened and everything on the page fits perfectly, I can execute scroll as much as I want, page won’t move, why would it? yknow what I mean?

I see what you mean but actually, my messages don’t fit my page because there is too much. I have something like 30 messages to test this functionality, so when I get on my chat page, I only see the 10 first messages, and I’d prefer to see the last 10 ones, just like Facebook Messenger or any other chat app.
I’ll try to upload you a video so you can see how my chat page is made :wink:

EDIT: Okaaaaay I may found something with your tip !
I added, like you said, much random buttons at the end of the page, and then it scrolled well. Maybe it’s related to my <ol></ol> and <li></li> elements ? Or the div that contains my messages ?
What do you think ?

Yeah that’s the problem, your page normally fits well and you can’t scroll down on it, you wanna scroll down on the messages, to be honest I have no idea what to do to fix it

1- what if instead of subscribing to the IonContent you would subscribe to the component holding all the messages?

2- when you added all those elements at the bottom and page extended and you could finally scroll, tell me, it scrolled the page down, but did it also affect the messages?

1- I think this solution will work, I just have to search how to do it cause I have no idea :smile:

2- It didn’t affect the messages, they were still there and well shown

EDIT:
1- Not sure if this solution will work after all, because I think scrollToBottom is an IonContent function :thinking:

remember how you used to ID ur ion-content?

image

and the ID went here

try to do the same but with the div, if that doesnt work try the ol and if that doesnt work either try the li xD

this.content.scrollToBottom() is not a function :frowning:

I don’t know how I can do it…

that logs in the console?

Yes !