Angular 5 Scroll to top on every Route click
Solution 1
There are some solutions, make sure to check them all :)
Option1:
The router outlet will emit the activate
event any time a new component is being instantiated, so we could use (activate)
to scroll (for example) to the top:
app.component.html
<router-outlet (activate)="onActivate($event)"></router-outlet>
app.component.ts
onActivate(event) {
// window.scroll(0,0);
window.scroll({
top: 0,
left: 0,
behavior: 'smooth'
});
//or document.body.scrollTop = 0;
//or document.querySelector('body').scrollTo(0,0)
...
}
As the smooth scroll is not implemented well in Safari, use, for exemple, this solution for a smooth scroll:
onActivate(event) {
let scrollToTop = window.setInterval(() => {
let pos = window.pageYOffset;
if (pos > 0) {
window.scrollTo(0, pos - 20); // how far to scroll on each step
} else {
window.clearInterval(scrollToTop);
}
}, 16);
}
If you wish to be selective, say not every component should trigger the scrolling, you can check it in an if
statement like this:
onActivate(e) {
if (e.constructor.name)==="login"{ // for example
window.scroll(0,0);
}
}
Option2:
Since Angular6.1, we can also use { scrollPositionRestoration: 'enabled' }
on eagerly loaded modules and it will be applied to all routes:
RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
It will also do the smooth scrolling, already. However this has the inconvenient for doing it on every routing.
Option3:
An other solution is to do the top scrolling on router animation. Add this in every transition where you want to scroll to the top:
query(':enter, :leave', style({ position: 'fixed' }), { optional: true })
Solution 2
If you face this problem in Angular 6, you can fix it by adding the parameter scrollPositionRestoration: 'enabled'
to app-routing.module.ts 's RouterModule:
@NgModule({
imports: [RouterModule.forRoot(routes,{
scrollPositionRestoration: 'enabled'
})],
exports: [RouterModule]
})
Solution 3
EDIT: For Angular 6+, please use Nimesh Nishara Indimagedara's answer mentioning:
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled'
});
Original Answer:
If all fails, then create some empty HTML element (eg: div) at the top (or desired scroll to location) with id="top" on template (or parent template):
<div id="top"></div>
And in component:
ngAfterViewInit() {
// Hack: Scrolls to top of Page after page view initialized
let top = document.getElementById('top');
if (top !== null) {
top.scrollIntoView();
top = null;
}
}
Solution 4
Now there's a built in solution available in Angular 6.1 with scrollPositionRestoration
option.
See my answer on Angular 2 Scroll to top on Route Change.
Solution 5
From Angular Version 6+ No need to use window.scroll(0,0)
For Angular version 6+
from @docs
Represents options to configure the router.
interface ExtraOptions {
enableTracing?: boolean
useHash?: boolean
initialNavigation?: InitialNavigation
errorHandler?: ErrorHandler
preloadingStrategy?: any
onSameUrlNavigation?: 'reload' | 'ignore'
scrollPositionRestoration?: 'disabled' | 'enabled' | 'top'
anchorScrolling?: 'disabled' | 'enabled'
scrollOffset?: [number, number] | (() => [number, number])
paramsInheritanceStrategy?: 'emptyOnly' | 'always'
malformedUriErrorHandler?: (error: URIError, urlSerializer: UrlSerializer, url: string) => UrlTree
urlUpdateStrategy?: 'deferred' | 'eager'
relativeLinkResolution?: 'legacy' | 'corrected'
}
One can use scrollPositionRestoration?: 'disabled' | 'enabled' | 'top'
in
Example:
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled'|'top'
});
And if one requires to manually control the scrolling, No need to use window.scroll(0,0)
Instead from Angular V6 common package has introduced ViewPortScoller
.
abstract class ViewportScroller {
static ngInjectableDef: defineInjectable({ providedIn: 'root', factory: () => new BrowserViewportScroller(inject(DOCUMENT), window) })
abstract setOffset(offset: [number, number] | (() => [number, number])): void
abstract getScrollPosition(): [number, number]
abstract scrollToPosition(position: [number, number]): void
abstract scrollToAnchor(anchor: string): void
abstract setHistoryScrollRestoration(scrollRestoration: 'auto' | 'manual'): void
}
Usage is pretty Straightforward Example:
import { Router } from '@angular/router';
import { ViewportScroller } from '@angular/common'; //import
export class RouteService {
private applicationInitialRoutes: Routes;
constructor(
private router: Router;
private viewPortScroller: ViewportScroller//inject
)
{
this.router.events.pipe(
filter(event => event instanceof NavigationEnd))
.subscribe(() => this.viewPortScroller.scrollToPosition([0, 0]));
}
Related videos on Youtube
raihan
Updated on January 13, 2022Comments
-
raihan over 2 years
I am using Angular 5. I have a dashboard where I have few sections with small content and few sections with so large content that I am facing a problem when changing router while going to top. Every time I need to scroll to go to top.
How can I solve this issue so that when I change the router, my view always stay at the top?
-
Cerbrus about 5 yearsPossible duplicate of Angular 2 Scroll to top on Route Change
-
-
Denis Savenko about 6 yearsThank you for advanced code and nice solution. But sometimes @Vega solution is better, because it solve many problems with animation and dynamic page height. You solution is good if you have long page with content and simple routing animation. I try it on page with many animation and dynamics block and it's looks not so good. I think sometimes we can sacrifice 'back position' for our app. But if not - you solution is the best what I see for Angular. Thank you again
-
Rob van Meeuwen about 6 yearsThis solution worked for me (tested on Chrome as well as Edge). The accepted solution didn't work for my project (Angular5)
-
Sahil Babbar about 6 yearsscroll events on
window
object are not working in angular 5. Any guesses why? -
Vega about 6 years@SahilBabbar, Check the body css, overflow:hiden ? what is its height?
-
Sahil Babbar about 6 years@Vega no. The height of the body is default and nothing is hard coded inside, as it is a normal Angular 5 application. Moreover take a look at Angular docs where they say that
scroll
events are blacklisted by ngzones. -
Vega about 6 yearsTry document.body.scrollTop = 0; or with old js document.querySelector('body').scrollTo(0,0), etc.. If those don't work provide an MCVE
-
Zub over 5 yearsyou are the best, Thank you so much!
-
rzvAmmar over 5 yearsThanks for the answer, solved my problem. Also I placed the code in my ngOnInit() method to make it work for Tabs navigation.
-
Vega over 5 years@RobvanMeeuwen, If my answer didn't work it probably you did not implement it the same way. This solution is manipulating directely the DOM which is not correct either safe
-
GeoRover over 5 years@Vega, that's why I called it a hack. Your solution is the proper one. Some folks here were not able to implement yours so I offered the fallback hack. They should refactor their code based on the version they are on at this point.
-
Manwal about 5 yearsThis is what I was looking for
RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
. Thanks -
Gangani Roshan about 5 yearsFrom all this solution is work for me. Thanks @GeoRover
-
Pankaj Prakash almost 5 yearsIs there any way for lazyloaded module?
-
GeoRover almost 5 yearsFor Angular 6+, please use Nimesh Nishara Indimagedara's answer.
-
dbeachy1 over 4 yearsNote that as of 6-Nov-2019 using Angular 8, at least, the
scrollPositionRestoration
property does not work with dynamic page content (i.e., where the page content is loaded asynchronously): see this Angular bug report: github.com/angular/angular/issues/24547 -
GCSDC about 4 yearsWorks great even without using an
id
(I have a singlerouter-outlet
on my app). I also did it on a more 'angular way':@ViewChild(MatSidenavContainer) sidenavContainer: MatSidenavContainer; onActivate() { this.sidenavContainer.scrollable.scrollTo({ left: 0, top: 0 }); }
-
Akitha_MJ about 4 yearswindow.scroll(0,0)
-
Vega over 3 years@PankajPrakash, I think other that configuring via the router solutions should work. Have you tried the via animation one?
-
Sajib Acharya over 3 yearsWeirdly, every solution works in some cases and fails in others. Angular scrolling to top is seriously flawed.
-
Boat about 3 yearsThis was the only one working for me as well. I am using ion-split-pane, and window.scroll doesn't seem to work for it.
-
Code Name Jack over 2 yearsI was able to inject ViewportScroller into my component. It woked.
-
rom5jp about 2 years
scrollTo(0, 0)
did'nt work for me, butscrollIntoView()
did. Thanks anyway! -
Bruno T. Abrahão about 2 yearsThanks! This solved my problem of scrolling to top after some action I had on my page, not exactly related to navigation.