Skip to content

Instantly share code, notes, and snippets.

@jsonberry
Last active February 20, 2019 04:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsonberry/2f1f9cdcc83e429ba7c3bdd984720e66 to your computer and use it in GitHub Desktop.
Save jsonberry/2f1f9cdcc83e429ba7c3bdd984720e66 to your computer and use it in GitHub Desktop.
Reactive Angular Scroll Position Restoration with RxJS
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { Event, NavigationEnd, NavigationStart, Router } from '@angular/router';
import { asyncScheduler } from 'rxjs';
import { filter, observeOn, scan } from 'rxjs/operators';
interface ScrollPositionRestore {
event: Event;
positions: { [K: number]: number };
trigger: 'imperative' | 'popstate';
idToRestore: number;
}
@Component({
selector: 'app-root',
template: `
<app-header></app-header>
<div>
<app-side-nav></app-side-nav>
<main #contentArea>
<router-outlet></router-outlet>
</main>
</div>
`
})
export class AppComponent implements OnInit {
@ViewChild('contentArea') private contentArea: ElementRef<HTMLMainElement>;
constructor(private router: Router) {}
ngOnInit() {
this.router.events
.pipe(
filter(
event =>
event instanceof NavigationStart || event instanceof NavigationEnd,
),
scan<Event, ScrollPositionRestore>((acc, event) => ({
event,
positions: {
...acc.positions,
...(event instanceof NavigationStart
? {
[event.id]: this.contentArea.nativeElement.scrollTop,
}
: {}),
},
trigger:
event instanceof NavigationStart
? event.navigationTrigger
: acc.trigger,
idToRestore:
(event instanceof NavigationStart &&
event.restoredState &&
event.restoredState.navigationId + 1) ||
acc.idToRestore,
})),
filter(
({ event, trigger }) => event instanceof NavigationEnd && !!trigger,
),
observeOn(asyncScheduler),
)
.subscribe(({ trigger, positions, idToRestore }) => {
if (trigger === 'imperative') {
this.contentArea.nativeElement.scrollTop = 0;
}
if (trigger === 'popstate') {
this.contentArea.nativeElement.scrollTop = positions[idToRestore];
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment