Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 6.1.0 - Restore scroll position not working as expected

Tags:

angular

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.

like image 291
Sorakthun Ly Avatar asked Nov 26 '22 01:11

Sorakthun Ly


2 Answers

Scroll position restoration

There are two steps involved here,

  1. Store the scroll position of the div. while navigating to the other page.
  2. Assign the stored values to the 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;
    }

}
like image 153
pkp Avatar answered Nov 28 '22 13:11

pkp


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 {}
like image 36
Christiaan van Vliet Avatar answered Nov 28 '22 14:11

Christiaan van Vliet