Skip to content

Instantly share code, notes, and snippets.

@codinronan
Forked from ValentinFunk/some.component.html
Created May 13, 2019 06:11
Show Gist options
  • Save codinronan/9804be1ac185c9ed5e9eefd623264762 to your computer and use it in GitHub Desktop.
Save codinronan/9804be1ac185c9ed5e9eefd623264762 to your computer and use it in GitHub Desktop.
Angular 2 Waypoints using ng2-scrollspy
<div scrollSpy>
<div [waypoint]="i" *ngFor="let i of [1,2,3,4,5,6,7,8]">
{{ i }}
</div>
</div>
import { Component, OnInit } from '@angular/core';
import { WaypointService } from '../../waypoint/waypoint.service';
import { Observable } from 'rxjs/Observable';
@Component({...})
export class SomeComponent implements OnInit {
constructor(
private waypointService: WaypointService
) { }
waypointHit$: Observable<string>;
ngOnInit() {
this.waypointHit$ = this.waypointService.getObservable();
this.waypointHit$.subscribe(id => console.log(id));
}
}
import { Directive, ElementRef, AfterViewInit, Input } from '@angular/core';
import { WaypointService } from './waypoint.service';
/**
* Returns absolute element top
*/
function getElementTop(el: HTMLElement) {
return el.getBoundingClientRect().top + window.pageYOffset;
}
/**
* Waypoint directive that can be used together with the WaypointService
* to listen to elements that are scrolled past.
*/
@Directive({
selector: '[waypoint]',
})
export class WaypointDirective implements AfterViewInit {
@Input('waypoint') id: string;
private el: HTMLElement;
constructor(
private elRef: ElementRef,
private waypointService: WaypointService
) {
this.el = this.elRef.nativeElement;
}
private subscription;
private position: number;
ngAfterViewInit() {
this.position = getElementTop(this.el);
this.waypointService.registerWaypoint(this.id, this.position);
}
}
// Angular Imports
import { NgModule } from '@angular/core';
import { WaypointDirective } from './waypoint.directive';
import { WaypointService } from './waypoint.service';
@NgModule({
imports: [
],
providers: [
WaypointService
],
declarations: [
WaypointDirective,
],
exports: [
WaypointDirective,
]
})
export class WaypointModule {
}
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';
import { ScrollSpyService } from 'ng2-scrollspy';
@Injectable()
export class WaypointService {
constructor(private scrollSpy: ScrollSpyService) {
}
private getElementAtPosition(scrollPos: number): string {
let id = null;
let bestDistance = Infinity; //smallest, positive distance
for (let entry of this.waypoints) {
let distance = scrollPos - entry.position + 10;
if (distance > 0 && distance < bestDistance) {
id = entry.id;
bestDistance = distance;
}
}
return id;
}
private waypoints: {id: string, position: number}[] = [];
registerWaypoint(id: string, position: number) {
this.waypoints.push({id, position});
}
getObservable() {
return this.scrollSpy.getObservable('window').flatMap((e) => {
let pos;
if (typeof e.target.scrollingElement !== 'undefined') {
pos = e.target.scrollingElement.scrollTop;
} else if (typeof e.target.scrollY !== 'undefined') {
pos = e.target.scrollY;
}
if (pos) {
let elemId = this.getElementAtPosition(pos);
if (elemId) {
return Observable.of(elemId);
}
}
return Observable.empty();
}).distinctUntilChanged();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment