feat: always scroll to top on page switch
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<div class="app-content" [attr.aria-hidden]="isLanguageSelectorOpen() ? 'true' : null" [attr.inert]="isLanguageSelectorOpen() ? '' : null">
|
<div class="app-content" [attr.aria-hidden]="isLanguageSelectorOpen() ? 'true' : null" [attr.inert]="isLanguageSelectorOpen() ? '' : null">
|
||||||
<router-outlet></router-outlet>
|
<router-outlet (activate)="scrollToTopAfterOutletActivation()"></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
import { DOCUMENT } from '@angular/common';
|
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
|
||||||
import {
|
import {
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
Component,
|
Component,
|
||||||
|
DestroyRef,
|
||||||
computed,
|
computed,
|
||||||
effect,
|
effect,
|
||||||
inject,
|
inject,
|
||||||
|
PLATFORM_ID,
|
||||||
signal,
|
signal,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import type { OnDestroy, OnInit } from '@angular/core';
|
import type { OnDestroy, OnInit } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { NavigationEnd, Router, RouterOutlet } from '@angular/router';
|
||||||
|
import { filter } from 'rxjs';
|
||||||
|
|
||||||
import type { LanguageCode } from '../languages/language.types';
|
import type { LanguageCode } from '../languages/language.types';
|
||||||
import type { LanguageOption } from './app.types';
|
import type { LanguageOption } from './app.types';
|
||||||
@@ -23,7 +27,10 @@ import { LanguageService } from './services/language.service';
|
|||||||
})
|
})
|
||||||
export class AppComponent implements OnInit, OnDestroy {
|
export class AppComponent implements OnInit, OnDestroy {
|
||||||
private readonly document = inject(DOCUMENT);
|
private readonly document = inject(DOCUMENT);
|
||||||
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
private readonly languageService = inject(LanguageService);
|
private readonly languageService = inject(LanguageService);
|
||||||
|
private readonly platformId = inject(PLATFORM_ID);
|
||||||
|
private readonly router = inject(Router);
|
||||||
|
|
||||||
protected readonly content = this.languageService.shellContent;
|
protected readonly content = this.languageService.shellContent;
|
||||||
protected readonly currentLanguageCode = this.languageService.languageCode;
|
protected readonly currentLanguageCode = this.languageService.languageCode;
|
||||||
@@ -47,6 +54,13 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
this.document.body.style.overflow = overflowValue;
|
this.document.body.style.overflow = overflowValue;
|
||||||
this.document.documentElement.style.overflow = overflowValue;
|
this.document.documentElement.style.overflow = overflowValue;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.router.events
|
||||||
|
.pipe(
|
||||||
|
filter((event): event is NavigationEnd => event instanceof NavigationEnd),
|
||||||
|
takeUntilDestroyed(this.destroyRef),
|
||||||
|
)
|
||||||
|
.subscribe((event: NavigationEnd): void => this.scrollToTopAfterRouteChange(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@@ -84,6 +98,37 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
return language === 'de' ? content.app.languageGerman : content.app.languageEnglish;
|
return language === 'de' ? content.app.languageGerman : content.app.languageEnglish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected scrollToTopAfterOutletActivation(): void {
|
||||||
|
if (!isPlatformBrowser(this.platformId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scrollDocumentToTop();
|
||||||
|
this.document.defaultView?.requestAnimationFrame((): void => this.scrollDocumentToTop());
|
||||||
|
this.document.defaultView?.setTimeout((): void => this.scrollDocumentToTop(), 0);
|
||||||
|
this.document.defaultView?.setTimeout((): void => this.scrollDocumentToTop(), 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
private scrollToTopAfterRouteChange(event: NavigationEnd): void {
|
||||||
|
if (!isPlatformBrowser(this.platformId) || event.urlAfterRedirects.includes('#')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scrollToTopAfterOutletActivation();
|
||||||
|
}
|
||||||
|
|
||||||
|
private scrollDocumentToTop(): void {
|
||||||
|
const scrollingElement = this.document.scrollingElement ?? this.document.documentElement;
|
||||||
|
|
||||||
|
scrollingElement.scrollTop = 0;
|
||||||
|
scrollingElement.scrollLeft = 0;
|
||||||
|
this.document.documentElement.scrollTop = 0;
|
||||||
|
this.document.documentElement.scrollLeft = 0;
|
||||||
|
this.document.body.scrollTop = 0;
|
||||||
|
this.document.body.scrollLeft = 0;
|
||||||
|
this.document.defaultView?.scrollTo({ top: 0, left: 0, behavior: 'auto' });
|
||||||
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.document.body.style.overflow = '';
|
this.document.body.style.overflow = '';
|
||||||
this.document.documentElement.style.overflow = '';
|
this.document.documentElement.style.overflow = '';
|
||||||
|
|||||||
Reference in New Issue
Block a user