RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled' })
This new feature in 6.1.0 doesn't work as expected. It seems that the ViewportScroller service tries to restore the scroll position before the DOM elements are populated so the max scroll height is essentially the device height. As a result, the scroll position restored is not doing the intended purpose.
I tried doing the following for custom scroll position restoration as suggested by the documentation but to no avail:
dataObsevable.pipe(withLatestFrom(scrollEvents)).subscribe(([list, e]) => {
this.data = list;
if (e.position) {
viewPort.scrollToPosition(e.position);
} else {
viewPort.scrollToPosition([0, 0]);
}
});
The position returned by the piped observable is correctly the value of the scroll position before the page was navigated from. However, it seems viewPort.scrollToPosition() tries to scroll the page before the DOM elements are done initialising so it's doing nothing.
Scroll position restoration
There are two steps involved here,
div
. while navigating to the other page.div
again when you come back to the page.if RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled' })
does not work, try the following code:
HTML:
Add the following events in the div
for which you want to restore scroll position
(scroll)="onScroll($event)" [scrollTop]="spt" [scrollLeft]="spl"
COMPONENT:
public spt:any;
public spl:any;
onScroll(event: any) {
sessionStorage.setItem('scroll',JSON.stringify({st:event.srcElement.scrollTop,sl:event.srcElement.scrollLeft}));
}
ngOnInit() {
if(sessionStorage.getItem('scroll'))
{
//console.log("scrollTop available")
var sp=JSON.parse(sessionStorage.getItem('scroll'));
this.spt=sp.st;
this.spl=sp.sl;
}
}
Unfortunately, the issue is still open and I could not get scrollPositionRestoration
to work properly. Raphael Balet's answer almost did the trick for me, but it seemed like the view was not ready yet when viewportScroller.scrollToPosition()
was called, even after I made sure it was called after Angular's ngAfterViewChecked()
lifecycle. Therefore I introduced a delay, which is not a clean solution but it worked:
app.component.ts
import { Component } from '@angular/core';
import { Router, Scroll } from '@angular/router';
import { ViewportScroller } from '@angular/common';
import { delay, filter } from 'rxjs/operators';
@Component({
selector: 'root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent {
constructor(router: Router, viewportScroller: ViewportScroller) {
router.events
.pipe(filter((e): e is Scroll => e instanceof Scroll))
.pipe(delay(1)) // <--------------------------- This line
.subscribe((e) => {
if (e.position) {
// backward navigation
viewportScroller.scrollToPosition(e.position);
} else if (e.anchor) {
// anchor navigation
viewportScroller.scrollToAnchor(e.anchor);
} else {
// forward navigation
viewportScroller.scrollToPosition([0, 0]);
}
});
}
}
For the router module, make sure that scrollPositionRestoration
is disabled, which is the default value.
app.router.ts
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With