Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gangadharjannu/ac667c0c6e0a79d2cdbc38f072349c29 to your computer and use it in GitHub Desktop.
Save gangadharjannu/ac667c0c6e0a79d2cdbc38f072349c29 to your computer and use it in GitHub Desktop.
This is an Angular 2 infinite scroll directive. It is simple, easy to use and very CPU-efficient.
// USAGE:
//
// When you attach the infiniteScroll directive to an element, it will emit the infiniteScrollAction
// @Output() event every time the user has scrolled to the bottom of the element. Your loadMoreArticles
// function can make an HTTP call and append the results to the articles list, for example. In doing this,
// you effectively increase the height of the element and thus begin the process of the infiniteScroll directive
// again, over and over until the element height stops increasing.
//
// <div class="container" infiniteScroll (infiniteScrollAction)="loadMoreArticles()">
// <div class="article" *ngFor="let article of articles">
// ...
// </div>
// </div>
//
// <div class="container" infiniteScroll [infiniteScrollContext]="'self'" (infiniteScrollAction)="loadMoreArticles()">
// <div class="article" *ngFor="let article of articles">
// ...
// </div>
// </div>
import { Directive, Input, Output, EventEmitter, ElementRef, HostListener, OnInit } from '@angular/core';
export interface Viewport {
h: number;
w: number;
}
// InfiniteScrollContext represents the context in which the directive will run.
//
// The default is 'document' and this will trigger your action when the end of
// your element has been reached relative to the documents scrollbar.
//
// If you use 'self', your action will be triggered when the end of your element
// has been reached relative to your elements own scrollbar.
export type InfiniteScrollContext = 'self' | 'document';
@Directive({
selector: '[infiniteScroll]',
})
export class InfiniteScrollDirective implements OnInit {
el: any;
viewport: Viewport;
canTriggerAction: boolean = true;
@Input() infiniteScrollContext: InfiniteScrollContext = 'document';
@Output() infiniteScrollAction: EventEmitter<any> = new EventEmitter();
@HostListener('scroll', ['$event']) onElementScroll() {
if (this.infiniteScrollContext === 'self') {
if (this.elementEndReachedInSelfScrollbarContext() && this.canTriggerAction) {
this.triggerAction();
}
}
}
constructor(private element: ElementRef) {
this.el = element.nativeElement;
this.viewport = this.getViewport(window);
}
ngOnInit() {
if (this.infiniteScrollContext === 'document') {
document.addEventListener('scroll', () => {
if (this.elementEndReachedInDocumentScrollbarContext(window, this.el) && this.canTriggerAction) {
this.triggerAction();
}
});
}
}
triggerAction() {
this.canTriggerAction = false;
this.infiniteScrollAction.emit(null);
}
elementEndReachedInSelfScrollbarContext(): boolean {
if (this.el.scrollTop + this.el.offsetHeight >= this.el.scrollHeight) {
this.canTriggerAction = true;
return true;
}
return false;
}
elementEndReachedInDocumentScrollbarContext(win: Window, el: any): boolean {
const rect = el.getBoundingClientRect();
const elementTopRelativeToViewport = rect.top;
const elementTopRelativeToDocument = elementTopRelativeToViewport + win.pageYOffset;
const scrollableDistance = el.offsetHeight + elementTopRelativeToDocument;
const currentPos = win.pageYOffset + this.viewport.h;
if (currentPos > scrollableDistance) {
this.canTriggerAction = true;
return true;
}
return false;
}
private getViewport(win: Window): Viewport {
// This works for all browsers except IE8 and before
if (win.innerWidth != null) {
return {
w: win.innerWidth,
h: win.innerHeight
};
}
// For IE (or any browser) in Standards mode
let d = win.document;
if (document.compatMode == 'CSS1Compat') {
return {
w: d.documentElement.clientWidth,
h: d.documentElement.clientHeight
};
}
// For browsers in Quirks mode
return {
w: d.body.clientWidth,
h: d.body.clientHeight
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment