I'm trying to code a page with two segments "chat" and "content". I want that one "chat" segment the page auto-scroll to the bottom with no effect. The chat is a <ion-list>
with several <ion-item>
.
<ion-list>
<ion-item> item 1 </ion-item>
<ion-item> item 2 </ion-item>
....
<ion-item> item 20 </ion-item>
<ion-item> item 21 </ion-item> <!-- user should see directly this item on bottom of the page -->
</ion-list>
I'm using Javascript, not typescript, and I don't wan't to use jQuery. Thanks :) Plus, when I go to "content" segment and go back to "chat" I want to auto-scroll again the chat.
Native scrolling can be enabled using overflow-scroll=”true” on your ion-content or using the $ionicConfigProvider to set it globally in current versions of Ionic.
Another solution is to "observe" changes in the scroll view and scroll automatically. i.e. if there are new HTML elements where the messages appear then scroll to the bottom.
export class MessagesPage implements OnInit, OnDestroy {
autoScroller: MutationObserver;
ngOnInit() {
this.autoScroller = this.autoScroll();
}
ngOnDestroy() {
this.autoScroller.disconnect();
}
autoScroll(): MutationObserver {
const autoScroller = new MutationObserver(this.scrollDown.bind(this));
autoScroller.observe(this.messagesList, {
childList: true,
subtree: true
});
return autoScroller;
}
scrollDown(): void {
this.scroller.scrollTop = this.scroller.scrollHeight;
this.messageEditor.focus();
}
private get messageEditor(): HTMLInputElement {
return <HTMLInputElement>document.querySelector('ion-input');
}
private get messagesList(): Element {
return document.querySelector('.messages');
}
private get scroller(): Element {
return this.messagesList.querySelector('.scroll-content');
}
}
Template:
<ion-content>
<ion-scroll scrollY="true" class="messages">
<ion-list>
<div *ngFor="let message of messages">
<p [innerHtml]="message.text"></p>
</div>
</ion-list>
</ion-scroll>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-input [(ngModel)]="message" type="text" placeholder="Write a message..." autocomplete="true" spellcheck="true" tappable></ion-input>
<ion-buttons end>
<button ion-button icon-only (click)="sendMessage()">
<ion-icon name="paper-plane"></ion-icon>
</button>
</ion-buttons>
</ion-toolbar>
</ion-footer>
(take from Ionic2CLI-Meteor-WhatsApp on Github)
Here's how I did it:
chatPage.html
<ion-content #content padding class="chatPage">
<ion-list no-lines>
<ion-item *ngFor="let msg of messages" >
<chat-bubble [message]="msg"></chat-bubble>
</ion-item>
</ion-list>
</ion-content>
The important bit in chatPage.html is #content
on <ion-content>
. I'll use the #content
identifier to obtain a reference to <ion-content>
in my chatPage.js using the ViewChild
.
Now for the actual scrolling logic:
chatPage.js
import {Component, ViewChild} from '@angular/core';
@Component({
templateUrl: 'build/pages/chatPage/chatPage.html',
queries: {
content: new ViewChild('content')
}
})
export class ChatPage {
constructor() {
}
//scrolls to bottom whenever the page has loaded
ionViewDidEnter(){
this.content.scrollToBottom(300);//300ms animation speed
}
}
Also, whenever my chatPage needs to show another chat message in the list (either a new message is received, or a new message is sent), I'm using the below code to scroll to the new bottom:
setTimeout(() => {
this.content.scrollToBottom(300);//300ms animation speed
});
Update for Typescript
Back when I gave this answer I was working with JavaScript version of Ionic 2 project. Over time I switched to TypeScript but I forgot to update the answer, so, here's a small update for chatPage.js(ts):
chatPage.ts
import {Component, ViewChild} from '@angular/core';
@Component({
templateUrl: 'chatPage.html'
})
export class ChatPage {
@ViewChild('content') content:any;
constructor() { }
//scrolls to bottom whenever the page has loaded
ionViewDidEnter(){
this.content.scrollToBottom(300);//300ms animation speed
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With