Created
January 4, 2017 10:40
-
-
Save ValentinFunk/63661e7ea251c92364a2ed1238f04264 to your computer and use it in GitHub Desktop.
Angular 2 Waypoints using ng2-scrollspy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div scrollSpy> | |
<div [waypoint]="i" *ngFor="let i of [1,2,3,4,5,6,7,8]"> | |
{{ i }} | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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