Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect if ion-content has a scrollbar?

I want to hide or show elements when there is or there isn't a scrollbar on ion-content. More specifically, I want to show a button (to load more items in a list) when there's no scrollbar and hide it where there is a scrollbar (so the loading of more items is done by ion-infinite-scroll).

My Ionic app will also be deployed to the desktop so users with large screens won't initially see a scrollbar and thus ion-infinite-scroll won't be triggered.

Here's a demo that showcases the issue:

home.page.html

<ion-header>
  <ion-toolbar>
    <ion-title>
      Ionic header
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
  <div class="ion-padding">
    <p *ngFor="let item of itemList">{{ item }}</p>

    <!-- How to hide this button when ion-content has a scrollbar? -->
    <!-- *ngIf="???" -->
    <ion-button (click)="incrementItemList(5)">Load more items</ion-button>
  </div>

  <ion-infinite-scroll (ionInfinite)="loadMoreItems($event)">
    <ion-infinite-scroll-content loadingSpinner="crescent"></ion-infinite-scroll-content>
  </ion-infinite-scroll>
</ion-content>

<ion-footer>
  <ion-toolbar>
    <ion-title>
      Ionic footer
    </ion-title>
  </ion-toolbar>
</ion-footer>

home.page.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {

  itemList: string[] = [];

  constructor() {}

  ionViewWillEnter() {
    this.incrementItemList(5);
  }

  incrementItemList(times: number) {
    for (let i = 1; i <= times; i++) {
      this.itemList.push(`Lorem ipsum dolor sit amet consectetur adipisicing elit. Quia placeat nam sapiente iusto eligendi`);
    }
  }

  loadMoreItems(event: any) {
    setTimeout(() => {
      this.incrementItemList(15);
      event.target.complete();
    }, 1000);
  }

}

I'm using Ionic 4.5.0 + Angular.

I have tried using getScrollElement, scrollHeight, clientHeight, offsetHeight, but with no success.

Any ideas?

like image 990
nunoarruda Avatar asked Jul 04 '19 07:07

nunoarruda


People also ask

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 I enable scrolling in Ionic?

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.


1 Answers

Update: I slept on it and then realised I was approaching it all wrong.

Here is a working example. It checks in three places to make sure it doesn't miss the scrollbar appearing:

  1. When the page loads
  2. When new content is added
  3. When the user scrolls

On my test environment, click the add button twice was coming in at EXACTLY the height of the screen so the button didn't always disappear. I added the ionScrollEnd check to provide an extra way of catching it.

You can remove the console.log's scattered around the code, I left it in to help you understand what was happening.

Example page:

<ion-header>
  <ion-toolbar>
    <ion-title>
      Scrollbar Test
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content [scrollEvents]="true" (ionScrollEnd)="onScrollEnd()">
  <div class="ion-padding">
    <p *ngFor="let item of itemList">{{ item }}</p>

    <ion-button *ngIf="!hasScrollbar" (click)="addMoreItemsButtonClick(5)">Load more items</ion-button>
  </div>

  <ion-infinite-scroll (ionInfinite)="loadMoreItems($event)">
    <ion-infinite-scroll-content loadingSpinner="crescent"></ion-infinite-scroll-content>
  </ion-infinite-scroll>
</ion-content>

<ion-footer>
  <ion-toolbar>
    <ion-title>
      Ionic footer
    </ion-title>
  </ion-toolbar>
</ion-footer>

Example code:

import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { IonContent } from '@ionic/angular';

@Component({
  selector: 'app-scrollheight',
  templateUrl: './scrollheight.page.html',
  styleUrls: ['./scrollheight.page.scss'],
})
export class ScrollheightPage implements OnInit {

  public hasScrollbar: Boolean = false;

  @ViewChild(IonContent) private content: IonContent;

  itemList: string[] = [];

  constructor() { }

  ngOnInit() {
    // check at startup
    this.checkForScrollbar();
  }

  ionViewWillEnter() {
    this.incrementItemList(5);
  }

  addMoreItemsButtonClick(quantity: number) {
    this.incrementItemList(quantity);

    // check after pushing to the list
    this.checkForScrollbar();
  }

  onScrollEnd() {
    // check after scrolling
    this.checkForScrollbar();
  }

  incrementItemList(times: number) {
    for (let i = 1; i <= times; i++) {
      this.itemList.push(`Lorem ipsum dolor sit amet consectetur adipisicing elit. Quia placeat nam sapiente iusto eligendi`);
    }
  }

  loadMoreItems(event: any) {
    setTimeout(() => {
      this.incrementItemList(15);

      event.target.complete();
    }, 1000);
  }

  checkForScrollbar() {
    this.content.getScrollElement().then((scrollElement) => {
      console.log("checking for scroll bar");
      console.log({scrollElement});
      console.log({scrollHeight: scrollElement.scrollHeight});
      console.log({clientHeight: scrollElement.clientHeight});
      this.hasScrollbar = (scrollElement.scrollHeight > scrollElement.clientHeight);
      console.log({hasScrollBar: this.hasScrollbar});
    });
  }
}
like image 64
rtpHarry Avatar answered Nov 15 '22 06:11

rtpHarry