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 &l
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)
Just do it:
public ionViewDidEnter(){
this.content.scrollToBottom(300);
}
I added a check to see if the user tried to scroll up.
<div style="overflow: scroll; height: xyz;" #scrollMe [scrollTop]="scrollMe.scrollHeight">
<div class="..."
*ngFor="..."
...>
</div>
</div>
This should work if your ion-list
element has a fixed height.
<ion-list id="item-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>
</ion-list>
[...]
<script>
var itemList = document.getElementById("item-list");
itemList.scrollTop = itemList.scrollHeight
</script>
First off all, @rinukkusu answer is right but it doesn't work on my case because <ion-content>
(parent of <ion-list>
) has some bugs with it (ionic developers are working on that), so I had to put that element with scroll:hidden
and create a second content inside to apply the auto-scroll.
Finally with the right (s)css I called the function on construtor
when the page loads and then each time the users clicks on "chat" segment.
chat.html
<!-- I create the segment and call the `autoScroll()` when users clicks on "chat" -->
<ion-toolbar primary class="toolbar-segment">
<ion-segment light [(ngModel)]="segment">
<ion-segment-button value="chat" (click)="autoScroll()">
Chat
</ion-segment-button>
<ion-segment-button value="profile">
Profile
</ion-segment-button>
</ion-segment>
</ion-toolbar>
<!--I wrote the css inline just as example.
DON'T do it on your project D: -->
<!-- overflow:hidden prevent the ion-content to scroll -->
<ion-content [ngSwitch]="segment" style="overflow: hidden;">
<!-- height: 100% to force scroll if the content overflows the container.
#chat-autoscroll is used by javascript.-->
<div class="content-scroll" id="chat-autoscroll" *ngSwitchWhen="'chat'" style="height: 100%; overflow: scroll">
(... make sure the content is bigger
than the container to see the auto scroll effect ...)
</div>
<!-- here it's just a normal scroll -->
<div *ngSwitchWhen="'profile'" class="content-scroll" style="height: 100%; overflow: auto">
(... content of profile segment ...)
</div>
</ion-content>
chat.js
constructor () {
// when the user opens the page, it shows the "chat" segment as initial value
this.segment = 'chat';
// when page loads, it calls autoScroll();
if (this.segment == 'chat') {
console.log('chat');
this.autoScroll();
};
}
/*Here comes the tricky.
If you don't use setTimeout, the console will say that
#chat-autoscroll doesn't exist in the first call (inside constructor).
This happens because the script runs before the DOM is ready.
I did a workaround with a timeOut of 10ms.
It's enough time to DOM loads and then autoScroll() works fine.
*/
autoScroll() {
setTimeout(function () {
var itemList = document.getElementById("chat-autoscroll");
itemList.scrollTop = itemList.scrollHeight;
}, 10);
}
Conclusion: The function is called twice. When the page is loaded (constructor) and each time the user comes back to "chat" segment. (click)="autoScroll()"
I hope this helps someone. If you know better way, let me know! I started playing with Angular2 and Ionic2 a couple of weeks ago so there is a lot of concepts/bases that I might be missing here.
Thanks :)
The Ionic has an option to do this and works pretty good: And this is the most appropriate way with angular 2+ and Ionic.
import { Content } from ‘ionic-angular’; export class CommentsPage{ @ViewChild(Content) content: Content; ionViewWillEnter(): void { this.scrollToBottom(); } scrollToBottom() { setTimeout(() => { this.content.scrollToBottom(); }); } }