-
-
Save iffa/9c820072135d25a6372d58075fe264dd to your computer and use it in GitHub Desktop.
| export class AppModule { | |
| constructor(private router: Router, private viewportScroller: ViewportScroller) { | |
| // Disable automatic scroll restoration to avoid race conditions | |
| this.viewportScroller.setHistoryScrollRestoration('manual'); | |
| 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]; | |
| } | |
| } |
Thanks for sharing!
Thanks!
thanks! but I have one question. is it ok to not unsubscribe from this subscription in case of just frontend app / in case of the app with server-side rendering?
It is also working for me, thanks!
I have one more improvement. Add the following line before calling this.handleScrollOnNavigation();
this.viewportScroller.setHistoryScrollRestoration('manual');
This way automatic scrolling from browser will be turned off so there are no scrolling results race conditions. In my case on navigating back I first saw scroll to top even before route change and before this.viewportScroller.scrollToPosition(current.position); was called,
@anbaran Thanks, updated code to reflect this.
👍
This may have been obvious to others but it wasn't to me. I had to change our app's router settings for scrollPositionRestoration to:
{ scrollPositionRestoration: 'disabled' } to get this workaround to work.
It took me a bit to figure that out. So if you are also wondering why this doesn't seem to work for you, check and make sure that is disabled.
<3