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; | |
} | |
} | |
} |