Forked from iffa/better-scroll-restoration-logic-angular.ts
Created
November 10, 2021 22:35
-
-
Save SiarheiBokuts/5f9cd94c998873b398343c673f838c4e to your computer and use it in GitHub Desktop.
Custom scroll position restoration logic for Angular 2+, that doesn't consider query parameter changes in route as forward navigation, thus preventing certain scenarios where you don't want query parameter changes to scroll-to-top as they would with 'scrollPositionRestoration: enabled'.
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
export class AppModule { | |
constructor(private router: Router, private viewportScroller: ViewportScroller) { | |
this.handleScrollOnNavigation(); | |
} | |
/** | |
* When route is changed, Angular interprets a simple query params change as "forward navigation" too. | |
* Using the pairwise function allows us to have both the previous and current router events, which we can | |
* use to effectively compare the two navigation events and see if they actually change route, or only | |
* the route parameters (i.e. selections stored in query params). | |
* | |
* Related to: https://github.com/angular/angular/issues/26744 | |
*/ | |
private handleScrollOnNavigation(): void { | |
this.router.events.pipe( | |
// import { Event } from '@angular/router' | |
filter((e: Event): e is Scroll => e instanceof Scroll), | |
pairwise() | |
).subscribe((e: Scroll[]) => { | |
const previous = e[0]; | |
const current = e[1]; | |
if (current.position) { | |
// Backward navigation | |
this.viewportScroller.scrollToPosition(current.position); | |
} else if (current.anchor) { | |
// Anchor navigation | |
this.viewportScroller.scrollToAnchor(current.anchor); | |
} else { | |
// Check if routes match, or if it is only a query param change | |
if (this.getBaseRoute(previous.routerEvent.urlAfterRedirects) !== this.getBaseRoute(current.routerEvent.urlAfterRedirects)) { | |
// Routes don't match, this is actual forward navigation | |
// Default behavior: scroll to top | |
this.viewportScroller.scrollToPosition([0, 0]); | |
} | |
} | |
}); | |
} | |
private getBaseRoute(url: string): string { | |
// return url without query params | |
return url.split('?')[0]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment