How to detect scroll to bottom of html element
Asked Answered
D

5

54

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?

Disinter answered 17/11, 2016 at 20:50 Comment(1)
this angular 2 module may help you npmjs.com/package/angular2-infinite-scrollOvi
M
52

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.

Malposition answered 2/3, 2017 at 4:53 Comment(6)
It is working but I want to scroll detect on perticular Section usign ID or Class. so How can I detect?Tun
It's works for body scroll not for the specific segment or div.Enuresis
hey @KMRifatulalom u can detect scroll of div by accessing it via IDMalposition
ex. var elem = document.getElementById("speakers_list"); var pos = elem.scrollTop + elem.offsetHeight; var max = elem.scrollHeight;Malposition
how to detect the only scrolldown eventNewhouse
use var prevPos(default: 0) and compare it with pos. ``` If (prevPos > pos) { /* scrolldown function */ } prevPos = pos; ```Malposition
S
99

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");
    }
}
Shark answered 26/4, 2018 at 8:36 Comment(9)
Had to change === to >= since the equation on left side is bigger when scrolled completely to the bottom of the element.Haemachrome
I didn't need the HostListener just the (scroll)='onScroll($event)'. Super simple.Curricle
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.Anthozoan
@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.Leasehold
Fires multiple times for me which was a deal breaker for me. Had to use AWolf's solutionAtlante
Fits perfect for my requirement thank youNiagara
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.scrollHeightMenchaca
The event is not firing... is there anything else that needs to be done?Cristinacristine
For me I needed to add target.offsetTop to offsetHeight and scrollTop, because if not, the scrollHeight is never reached. I think that is needed, when you have a parent element, that has padding-topMoleskins
M
52

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.

Malposition answered 2/3, 2017 at 4:53 Comment(6)
It is working but I want to scroll detect on perticular Section usign ID or Class. so How can I detect?Tun
It's works for body scroll not for the specific segment or div.Enuresis
hey @KMRifatulalom u can detect scroll of div by accessing it via IDMalposition
ex. var elem = document.getElementById("speakers_list"); var pos = elem.scrollTop + elem.offsetHeight; var max = elem.scrollHeight;Malposition
how to detect the only scrolldown eventNewhouse
use var prevPos(default: 0) and compare it with pos. ``` If (prevPos > pos) { /* scrolldown function */ } prevPos = pos; ```Malposition
F
22

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>
Footpace answered 17/11, 2016 at 22:1 Comment(2)
Here is the demo of the host listener directive so you can see the listener in action.Footpace
The scroll event is not working for me, I'm using Angular 6, If I change this with window:scroll, It works.Echelon
C
0

I am literally working on this now and found that this is the most versatile use case for "me."

As YASH DAVE mentioned, using a Host Listener is your best bet for an Angular 'onScroll' implementation. However, 'Window: Scroll' didn't work for my use case (a table injected within a Dashboard). So I had luck doing this


@HostListener('scroll', ['$event.target'])
 onScroll(elem){
  if(( elem.offsetHeight + elem.scrollTop) >=  elem.scrollHeight) {
     console.log("It's Lit");
  }
}'

CSS:

:host {
     display: block;
     max-height: 700px;
     width: 100%;
     overflow-y: scroll;
     scroll-behavior: auto;
 }

Explanation:

  • Basically the generic "scroll" listens for the scroll event occurring on the host element.
  • passes the element reference that triggered the scroll event via $event.target to my onScroll(elem) method
  • Then I take the element reference and determine if the offsetHeight and ScrollTop is greater than the scrollHeight (yes this is different then how others have implemented this) reference: mVChr's Implementation
  • Then boom, enjoy.
  • Note: If you just need a, and I can't stress this enough, simple solution just add a (scroll) event listener on the particular element

Additionally, review This for an insight on offsetHeight, clientHeight, scrollHeight.

Crenellate answered 2/4, 2019 at 23:38 Comment(0)
S
0

Try this, it will work

@HostListener('body:scroll', ['$event'])

Spay answered 25/5, 2021 at 11:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.