How to detect scroll to bottom of html element

89,013

Solution 1

I think that all you want to do is detect the position of scroll.

@HostListener("window:scroll", ["$event"])
onWindowScroll() {
//In chrome and some browser scroll is given to body tag
let pos = (document.documentElement.scrollTop || document.body.scrollTop) + document.documentElement.offsetHeight;
let max = document.documentElement.scrollHeight;
// pos/max will give you the distance between scroll bottom and and bottom of screen in percentage.
 if(pos == max )   {
 //Do your action here
 }
}

Also don't forget to import HostListener from @angular/core.

Solution 2

You could check whether the user has scrolled to the bottom or not in the below way...

Html file

<div (scroll)="onScroll($event)">
    ...
    ...
</div>

typescript file

onScroll(event: any) {
    // visible height + pixel scrolled >= total height 
    if (event.target.offsetHeight + event.target.scrollTop >= event.target.scrollHeight) {
      console.log("End");
    }
}

Solution 3

You could do this with an observable that's tracking the scroll event of your container.

Or you could create a host listener for your component that's listening for the scroll event. Please have a look at this SO question. (I haven't tested it with a host listener but that should work.)

Add the following code to your component for observable approach (I've copied some of the code from this blog post. ):

  ngOnInit() {
    /*
     * Create the observable from an event, in this case, the window scroll event
     * then map each event so we can get a new value from it
     * i.e. over time, we are just dealing with a collection:
     * (map [e1, e2, e3, ...]) -> [t1, t2, t3, ...]
     */
    let tracker = document.getElementById('th-infinite-scroll-tracker');

    let windowYOffsetObservable = Observable.fromEvent(tracker, 'scroll').map(() => {
      // I don't actually care about the event, I just need to get the window offset (scroll position)
      return tracker.scrollTop;
    });

    // subscribe to our Observable so that for each new item, our callback runs
    // this is our event handler
    let scrollSubscription = windowYOffsetObservable.subscribe((scrollPos) => {
      let limit = tracker.scrollHeight - tracker.clientHeight;
      console.log(scrollPos, limit);
      if (scrollPos === limit) {
        alert('end reached');
      }
    });
  }

Update

Another way and probably the best would be to create a directive for your tracking logic. Then you can easily use HostListener to bind to the scroll event.

Typescript code:

import {
  Directive, HostListener
}
from '@angular/core';

@Directive({
  selector: '[scrollTracker]'
})
export class ScrollTrackerDirective {
  @HostListener('scroll', ['$event']);

  onScroll(event) {
    // do tracking
    // console.log('scrolled', event.target.scrollTop);
    // Listen to click events in the component
    let tracker = event.target;

    let limit = tracker.scrollHeight - tracker.clientHeight;
    console.log(event.target.scrollTop, limit);
    if (event.target.scrollTop === limit) {
      alert('end reached');
    }
  }

  constructor() {}
}

Markup in your component (add your directive)

<div id="th-infinite-scroll-tracker" style="overflow-y:scroll; height: 500px;" scrollTracker>
  .... your container with scrollbar ...
</div>
Share:
89,013

Related videos on Youtube

CommonSenseCode
Author by

CommonSenseCode

Software Skills: JavaScript NodeJS Golang React Redis Android Ionic/Cordova Framework XML, HTML, CSS, Sass, Less jQuery, Bootstrap MongoDB SQLite, Postgres &amp; MySQL Git, Github, Bitbucket &amp; Gitlab Linux Agile Development Unit Testing

Updated on January 18, 2022

Comments

  • CommonSenseCode
    CommonSenseCode over 2 years

    I have this element that I'm referencing by Id:

        let infiniteScrollElement = document.getElementById('th-infinite-scroll-tracker');
    

    I need to listen when the browser is has reached the bottom of the element.

    How to achieve this?

  • Hasmukh Ahir
    Hasmukh Ahir almost 7 years
    It is working but I want to scroll detect on perticular Section usign ID or Class. so How can I detect?
  • K M Rifat ul alom
    K M Rifat ul alom almost 7 years
    It's works for body scroll not for the specific segment or div.
  • YASH DAVE
    YASH DAVE almost 7 years
    hey @KMRifatulalom u can detect scroll of div by accessing it via ID
  • YASH DAVE
    YASH DAVE almost 7 years
    ex. var elem = document.getElementById("speakers_list"); var pos = elem.scrollTop + elem.offsetHeight; var max = elem.scrollHeight;
  • AWolf
    AWolf about 6 years
    Here is the demo of the host listener directive so you can see the listener in action.
  • user2340939
    user2340939 almost 6 years
    Had to change === to >= since the equation on left side is bigger when scrolled completely to the bottom of the element.
  • Bhimashankar Mantur
    Bhimashankar Mantur over 5 years
    how to detect the only scrolldown event
  • Steve
    Steve over 5 years
    I didn't need the HostListener just the (scroll)='onScroll($event)'. Super simple.
  • YASH DAVE
    YASH DAVE over 5 years
    use var prevPos(default: 0) and compare it with pos. ``` If (prevPos > pos) { /* scrolldown function */ } prevPos = pos; ```
  • Rohit Khatri
    Rohit Khatri over 5 years
    The scroll event is not working for me, I'm using Angular 6, If I change this with window:scroll, It works.
  • Vikas Kandari
    Vikas Kandari over 4 years
    it did't need HostListener simple function will also work make sure you use isPlatformBrowser with it also HostListener scroll event continuously refreshes the whole Angular object which makes whole application heavy. don't use scroll event with HostListener.
  • AkRoy
    AkRoy over 4 years
    @NarottamGoyal when i reach to the end i make a service call and append the data to the table, but the scroller remains at the end and it makes a service call again and again. can you help on this.
  • sotn
    sotn almost 4 years
    Fires multiple times for me which was a deal breaker for me. Had to use AWolf's solution
  • Geek
    Geek about 3 years
    Fits perfect for my requirement thank you
  • mvoelcker
    mvoelcker over 2 years
    I was still having problems with this solution, turns out that for some cases the scrollTop was about .25 lower than the necessary to add up to total height. My solution was simply to round up like this: event.target.offsetHeight + Math.ceil(event.target.scrollTop) >= event.target.scrollHeight
  • Awybin
    Awybin about 2 years
    The event is not firing... is there anything else that needs to be done?