Scroll Measure Service - ScrollMeasure
An angular service that uses the Scroll Strategies from Angular Materials to create an observable that emits an event whenever a user scrolls to the bottom of the page.
This service allows an element contained in a bootstrap to measure the scroll position of the entire page, and this allows for infinite scrolling without creating a "bounding box"
scroll-measure-service.ts
import {EventEmitter, Injectable} from "@angular/core";
import {ScrollDispatcher} from "@angular/material";
import {Observable} from "rxjs/Observable";
import {Subscription} from "rxjs/Subscription";
class ScrollableDetails{
elementName:string;
//Since we are using viewChild, what is the type here?
elementRef;
pageHeight:number;
scrollPos:number;
clientHeight:number;
updateStats(){
let scrollWindow = this.elementRef;
this.clientHeight = scrollWindow.clientHeight;
this.pageHeight = scrollWindow.scrollHeight;
this.scrollPos = scrollWindow.scrollTop;
}
}
@Injectable()
export class ScrollMeasure{
//Collection of all scrollable objects
scrollableCollection:ScrollableDetails[] = [];
pagationTrigger:EventEmitter<any> = new EventEmitter<any>();
scrollSubscriptions:Subscription;
//@TODO: Figure out way to make this reasonably Configerable
static pageLengths:number = 2;
//Injected services
constructor(private _scroll:ScrollDispatcher){
this.initScrollMeasure();
}
initScrollMeasure(){
//Stream that sends all scrollable references whenever a scroll event is set off.
//Stream that updates all entries during scroll event
let bufferTime = 200; //ms
this.scrollSubscriptions = this._scroll.scrolled(200,()=>{this.scrollableCollection.forEach(ScrollableObject=>{
let scrollWindow = ScrollableObject.elementRef;
ScrollableObject.updateStats();
if(ScrollMeasure._calculateHasHitBottom(ScrollableObject)){
this.pagationTrigger.emit();
}
})});
}
ngOnDestroy(){
this.scrollSubscriptions.unsubscribe();
}
/*
Returns a stream that emits an event whenever a scroll object has hit the bottom of the page.
*/
subscribeToPaginationEmitter(functionToPerform):void{
this.scrollSubscriptions.add(this.pagationTrigger.subscribe(functionToPerform));
}
static _calculateHasHitBottom(scrollable:ScrollableDetails):boolean{
const triggerDistance = ScrollMeasure.pageLengths * scrollable.clientHeight;
return scrollable.scrollPos + scrollable.clientHeight + triggerDistance >= scrollable.pageHeight;
}
register(elementReference):void{
let newEntry = new ScrollableDetails();
newEntry.elementRef = elementReference.nativeElement;
newEntry.updateStats();
this.scrollableCollection.push(newEntry);
}
}