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. Can anyone help me to solve this issue so that when I change the router my view always stay at the top.
Thanks in advance.
A router outlet will emit an activate event any time a new component is being instantiated, so (activate)
event could be 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);
//or document.body.scrollTop = 0;
//or document.querySelector('body').scrollTo(0,0)
...
}
or using this answer to 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:
onActivate(e) {
if (e.constructor.name)==="login"{ // for example
window.scroll(0,0);
}
}
Since Angular6.1, we can also use
{ scrollPositionRestoration: 'enabled' }
on eagerly loaded modules or just in app.module and it will be applied to all routes:
RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
It will also do the smooth scrolling
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]
})
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;
}
}
Now there's a built in solution available in Angular 6.1 with scrollPositionRestoration
option.
Although @Vega provides the direct answer to your question, there are issues. It breaks the browser's back/forward button. If you're user clicks the browser back or forward button, they lose their place and gets scrolled way at the top. This can be a bit of a pain for your users if they had to scroll way down to get to a link and decided to click back only to find the scrollbar had been reset to the top.
Here's my solution to the problem.
export class AppComponent implements OnInit {
isPopState = false;
constructor(private router: Router, private locStrat: LocationStrategy) { }
ngOnInit(): void {
this.locStrat.onPopState(() => {
this.isPopState = true;
});
this.router.events.subscribe(event => {
// Scroll to top if accessing a page, not via browser history stack
if (event instanceof NavigationEnd && !this.isPopState) {
window.scrollTo(0, 0);
this.isPopState = false;
}
// Ensures that isPopState is reset
if (event instanceof NavigationEnd) {
this.isPopState = false;
}
});
}
}
In my case I just added
window.scroll(0,0);
in ngOnInit()
and its working fine.
Here is a solution that only scrolls to top of Component if first time visiting for EACH component (in case you need to do something different per component):
In each Component:
export class MyComponent implements OnInit {
firstLoad: boolean = true;
...
ngOnInit() {
if(this.firstLoad) {
window.scroll(0,0);
this.firstLoad = false;
}
...
}
I keep looking for a built in solution to this problem like there is in AngularJS. But until then this solution works for me, It's simple, and preserves back button functionality.
app.component.html
<router-outlet (deactivate)="onDeactivate()"></router-outlet>
app.component.ts
onDeactivate() {
document.body.scrollTop = 0;
// Alternatively, you can scroll to top by using this other call:
// window.scrollTo(0, 0)
}
Answer from zurfyx original post
You just need to create a function which contains adjustment of scrolling of your screen
for example
window.scroll(0,0) OR window.scrollTo() by passing appropriate parameter.
window.scrollTo(xpos, ypos) --> expected parameter.
Try this:
app.component.ts
import {Component, OnInit, OnDestroy} from '@angular/core';
import {Router, NavigationEnd} from '@angular/router';
import {filter} from 'rxjs/operators';
import {Subscription} from 'rxjs';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit, OnDestroy {
subscription: Subscription;
constructor(private router: Router) {
}
ngOnInit() {
this.subscription = this.router.events.pipe(
filter(event => event instanceof NavigationEnd)
).subscribe(() => window.scrollTo(0, 0));
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
export class AppComponent {
constructor(private router: Router) {
router.events.subscribe((val) => {
if (val instanceof NavigationEnd) {
window.scrollTo(0, 0);
}
});
}
}
Component: Subscribe to all routing events instead of creating an action in the template and scroll on NavigationEnd b/c otherwise you'll fire this off on bad navs or blocked routes, etc... This is a sure fire way to know that if a route successfully is navigated to, then sooth scroll. Otherwise, do nothing.
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, OnDestroy {
router$: Subscription;
constructor(private router: Router) {}
ngOnInit() {
this.router$ = this.router.events.subscribe(next => this.onRouteUpdated(next));
}
ngOnDestroy() {
if (this.router$ != null) {
this.router$.unsubscribe();
}
}
private onRouteUpdated(event: any): void {
if (event instanceof NavigationEnd) {
this.smoothScrollTop();
}
}
private smoothScrollTop(): void {
const scrollToTop = window.setInterval(() => {
const pos: number = window.pageYOffset;
if (pos > 0) {
window.scrollTo(0, pos - 20); // how far to scroll on each step
} else {
window.clearInterval(scrollToTop);
}
}, 16);
}
}
HTML
<router-outlet></router-outlet>
try this
@NgModule({
imports: [RouterModule.forRoot(routes,{
scrollPositionRestoration: 'top'
})],
exports: [RouterModule]
})
this code supported angular 6<=
来源:https://stackoverflow.com/questions/48048299/angular-5-scroll-to-top-on-every-route-click