Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ionic 4 ion-content scroll to bottom

I am creating a chat page using Ionic 4 and I'm trying to make it automatically scroll to the bottom of the page. I did it like this and it's not working:

import { IonContent } from "@ionic/angular";

export class ChatroomPage implements OnInit {
    messageForm: FormGroup;
    messages: any[];
    messenger: any;
    @ViewChild(IonContent) content: IonContent;

    constructor(
        private navExtras: NavExtrasService,
        private api: RestApiService,
        private httpNative: HTTP
    ) { }

    ngOnInit() {
        this.content.scrollToBottom(300);
    }
}

In the html file:

<ion-header>
    <ion-toolbar color="primary">
        <ion-title>Chatroom</ion-title>
            </ion-toolbar>
        </ion-header>

        <!-- display previous message -->
        <ion-content padding id="content"> 

        <ion-list>
            <ion-item *ngFor="let message of messages">
                {{ message.message }}
            </ion-item>
        </ion-list>

        </ion-content>

    <!-- chat message input -->
    <ion-footer>
        <form [formGroup]="messageForm" (submit)="sendMessage()" (keydown.enter)="sendMessage()">
            <ion-input formControlName="message" type="text" placeholder="Enter your message"></ion-input>
            <ion-button type="submit">Send</ion-button>
        </form>
    </ion-footer>

The error displayed is:

ng:///ChatroomPageModule/ChatroomPage_Host.ngfactory.js:5 ERROR TypeError: Cannot read property 'scrollToBottom' of undefined

Please enlighten me what did I do wrong. Most tutorials I found are using Ionic 3 and they use Content from ionic-angular instead of IonContent from @ionic/angular. I cannot seem to use Content in Ionic 4 as it doesn't have the scrollToBottom method.

like image 684
tyn Avatar asked Mar 12 '19 08:03

tyn


People also ask

How do you make ion-content not scrollable?

In order to place elements outside of the scrollable area, slot="fixed" can be added to the element. This will absolutely position the element placing it in the top left. In order to place the element in a different position, style it using top, right, bottom, and left.

How do you make an ion card scrollable?

Just want to add for future reference that in general, if you just want to scroll inside the ion-card-content, adding the overflow: scroll; on the ion-card-content element css (besides the display: flex; flex-direction: column; on the ion-card) works.

How do you do infinite scrolling with ions?

You can access the infinite scroll by using the standard <ion-infinite-scroll> and <ion-infinite-scroll-content> component. The expression (ionInfinite) = "loadData($event)" assigned in the <ion-infinite-scroll> is called when the user reaches close to the defined distance.


7 Answers

@ViewChild(IonContent) content: IonContent;
scrollToBottom() {
    setTimeout(() => {
      if (this.content.scrollToBottom) {
        this.content.scrollToBottom();
      }
    }, 400);
  }

Anywhere in function use:

this.scrollToBottom();
like image 135
Nikhil Tyagi Avatar answered Nov 07 '22 08:11

Nikhil Tyagi


You can reach the bottom of the content with the method scrollToBottom()

scrollToBottom(duration?: number) => Promise<void>

Add an ID to the ion-content

<ion-content #content>
</ion-content>

Get the content ID in .ts and call the scrollToBottom method with a chosen duration

@ViewChild('content') private content: any;

ngOnInit() {
  this.scrollToBottomOnInit();
}

scrollToBottomOnInit() {
  this.content.scrollToBottom(300);
}

https://ionicframework.com/docs/api/content

EDIT:

ViewChild gets the correct data with the provided content ID

@ViewChild('content') private content: any;

ngOnInit vs ionViewDidEnter / ionViewWillEnter

ngOnInit doesn't trigger if you come back from a navigation stack, ionViewWillEnter / ionViewDidEnter will. So if you place the function in ngOnInit, the scrollToBottom won't work if you navigate back.

like image 31
Tomas Vancoillie Avatar answered Nov 07 '22 08:11

Tomas Vancoillie


Due to recent changes on ionic 4, I found the code in suggested answer no longer works for me. Hope this helps all the new comers.

import { IonContent } from '@ionic/angular';

export class IonicPage implements OnInit {
@ViewChild(IonContent, {read: IonContent, static: false}) myContent: IonContent;

  constructor() {}

  ScrollToBottom(){
    setTimeout(() => {
      this.myContent.scrollToBottom(300);
   }, 1000);

  }
}

No id specified in .html file for < ion-content >

Official documentation refers to ion-content. Ionic version used listed below at the time of this post.

Ionic CLI                     : 5.4.13
Ionic Framework               : @ionic/angular 4.11.3
@angular/cli                  : 8.1.3
like image 34
Kevin Ng Avatar answered Nov 07 '22 09:11

Kevin Ng


Most of your code is fine. You just need to do 2 changes and that should work for you, in Ionic 4. Here are the changes:

Change 1 (HTML FILE):

Replace:

<ion-content padding id="content">

with:

<ion-content padding #content>

Change 2 (TS FILE):

Replace:

scrollToBottomOnInit() {
  this.content.scrollToBottom(300);
}

with:

scrollToBottomOnInit() {
    setTimeout(() => {
        if (this.content.scrollToBottom) {
            this.content.scrollToBottom(400);
        }
    }, 500);
}

NOTE:

If you do not import IonContent (similar to the way you already did), the code will fail to compile and you will see console errors such as this:

ERROR Error: Uncaught (in promise): ReferenceError: Cannot access 'MessagesPageModule' before initialization

where MessagesPageModule is the Module associated with the page that you are trying to implement the feature in.

like image 36
Devner Avatar answered Nov 07 '22 08:11

Devner


Tomas Vancoillie is right, but when you add new text and add to list, it won't push it up above input text. Therefore to push text to array and update view to bottom again use ngZone.

1.

import { Component, ViewChild,NgZone } from '@angular/core';
  1. In constructor add
public _zone: NgZone
  1. Call your function
this._zone.run(() => {
  setTimeout(() => {
    this.contentchat.scrollToBottom(300);
  });
}); 
like image 40
codingwithtashi Avatar answered Nov 07 '22 07:11

codingwithtashi


This works for me on December 2019.

.html

<ion-content #content>

</ion-content>

.ts

@ViewChild('content', { static: false }) content: IonContent;

constructor(){}

 ngOnInit(): void {
    this.scrollToBottom();
  }


 scrollToBottom(): void {
    this.content.scrollToBottom(300);
  }
like image 28
Sampath Avatar answered Nov 07 '22 09:11

Sampath


This finally worked for me. You can try it out.

.ts

import { Component, OnInit, ViewChild, NgZone } from '@angular/core';

/.. class declaration .../

@ViewChild('content') content : IonContent;

constructor(public _zone: NgZone){
}

ngOnInit(): void {
    this.scrollToBottom();
}

scrollToBottom()
{
    this._zone.run(() => {

      const duration : number = 300;

      setTimeout(() => {
        
        this.content.scrollToBottom(duration).then(()=>{

          setTimeout(()=>{

            this.content.getScrollElement().then((element:any)=>{

              if (element.scrollTopMax != element.scrollTop)
              {
                // trigger scroll again.
                this.content.scrollToBottom(duration).then(()=>{

                  // loaded... do something

                });
              }
              else
              {
                // loaded... do something
              }
            });
          });
        });

      },20);
    }); 
}
like image 35
Ifeanyi Amadi Avatar answered Nov 07 '22 09:11

Ifeanyi Amadi