Problem. Router option scrollPositionRestoration: 'enabled|top' doesn't work.
Also see the issue.
Problem. Router option scrollPositionRestoration: 'enabled|top' doesn't work.
Also see the issue.
| // … | |
| @NgModule({ | |
| imports: [ | |
| AppRouterModule, | |
| // … | |
| ], | |
| bootstrap: [RootComponent], | |
| providers: [ | |
| // … | |
| { | |
| provide: ViewportScroller, | |
| useFactory: () => new CustomViewportScroller('#main', inject(DOCUMENT), inject(ErrorHandler)) | |
| } | |
| ] | |
| }) | |
| export class AppModule {} |
| import { ViewportScroller } from '@angular/common'; | |
| import { ErrorHandler } from '@angular/core'; | |
| export class CustomViewportScroller implements ViewportScroller { | |
| private offset: () => [number, number] = () => [0, 0]; | |
| private readonly window: Window; | |
| constructor( | |
| private readonly scrollElementSelector: string, | |
| private readonly document: Document, | |
| private readonly errorHandler: ErrorHandler | |
| ) { | |
| this.window = this.document.defaultView; | |
| } | |
| public setOffset(offset: [number, number] | (() => [number, number])): void { | |
| if (Array.isArray(offset)) { | |
| this.offset = () => offset; | |
| } else { | |
| this.offset = offset; | |
| } | |
| } | |
| public getScrollPosition(): [number, number] { | |
| const scrollEl = this.document.querySelector(this.scrollElementSelector); | |
| if (this.supportsScrolling() && scrollEl) { | |
| return [scrollEl.scrollLeft, scrollEl.scrollTop]; | |
| } | |
| return [0, 0]; | |
| } | |
| public scrollToPosition(position: [number, number]): void { | |
| const scrollEl = this.document.querySelector(this.scrollElementSelector); | |
| if (this.supportsScrolling() && scrollEl) { | |
| scrollEl.scrollTo(...position); | |
| } | |
| } | |
| public scrollToAnchor(anchor: string): void { | |
| if (!this.supportsScrolling()) { | |
| return; | |
| } | |
| try { | |
| const elSelectedById = this.document.querySelector(`#${anchor}`); | |
| if (elSelectedById) { | |
| this.scrollToElement(elSelectedById); | |
| return; | |
| } | |
| const elSelectedByName = this.document.querySelector(`[name='${anchor}']`); | |
| if (elSelectedByName) { | |
| this.scrollToElement(elSelectedByName); | |
| return; | |
| } | |
| } catch (e) { | |
| this.errorHandler.handleError(e); | |
| } | |
| } | |
| public setHistoryScrollRestoration(scrollRestoration: 'auto' | 'manual'): void { | |
| if (this.supportsScrolling()) { | |
| return; | |
| } | |
| const history = this.window.history; | |
| if (history && history.scrollRestoration) { | |
| history.scrollRestoration = scrollRestoration; | |
| } | |
| } | |
| private scrollToElement(el: Element): void { | |
| const rect = el.getBoundingClientRect(); | |
| const left = rect.left + this.window.scrollX; | |
| const top = rect.top + this.window.scrollY; | |
| const [offsetX, offsetY] = this.offset(); | |
| this.window.scrollTo(left - offsetX, top - offsetY); | |
| } | |
| private supportsScrolling(): boolean { | |
| try { | |
| return !!this.window && !!this.window.scrollTo; | |
| } catch { | |
| return false; | |
| } | |
| } | |
| } |