Machado
Machado

Reputation: 10314

Router anchorScrolling does not work with Material's mat-sidenav-container[fullscreen]

The RouterModule anchor scroll is based on the viewport scrollable area, as mat-sidenav-container sets ifself as 100% height when used with the fullscreen attribute, there's no viewport overflow for RouterModule to change.

<mat-sidenav-container fullscreen>
    <mat-sidenav-content></mat-sidenav-content>
</mat-sidenav-content>

In the example above, all the scrollable content lives inside mat-sidenav-content.

Is there a way for RouterModule to use mat-sidenav-container instead of the viewport as a scrolling container reference?

See the StackBlitz Example. See the working version without fullscreen.

Upvotes: 3

Views: 1590

Answers (3)

breity
breity

Reputation: 11

For an Angular/Angular Material 16 application with mat-sidenav-container in app.component.html, I was able to get anchor scrolling working by adding the following css to AppComponent:

mat-sidenav-container, mat-sidenav-content {
  overflow: unset;
}

You'll want to test in your own application to make sure this doesn't mess up any other scrolling behavior.

Upvotes: 1

Dibyodyuti Mondal
Dibyodyuti Mondal

Reputation: 161

I am having the exact same problem. I solved it by:

  1. For the mat-side-nav-container, instead of setting 'height', I set 'min-height' as 100%, so that the scrollable element is the body, and not the sidenav container, but in case the content is less than the viewport, the container will still stretch to cover it. Please remember, this may affect your layout depending on your implementation, but this is absolutely essential for this solution to work.
  2. The height of the mat-toolbar (above the mat-sidenav-container) is 64px and the margin I keep for the element being scrolled is 16px, therefore (64 + 16) is the y-offset
  3. In app.module.ts, inside imports for the NgModule
RouterModule.forRoot(
      routes,
      {
        anchorScrolling: 'enabled',
        scrollOffset: [0, 64 + 16]
      }),
  1. Assuming the mat-sidenav-container lives in app.component.html, I added the following to app.component.ts inside ngOnInit(). (Please remember to take precautions against memory leaks due to subscriptions, although this is the app-component, so it doesn't really matter)
this.router.events
        .pipe(

          //take only scroll events that have an anchor specified
          filter(e => e instanceof Scroll && !!e.anchor),

          //wait for the DOM to resolve. It worked with 10, but it was a small test case
          //so I used 100 just in case
          delay(100),

          //take the element that the anchor points to
          map((e: Scroll) => document.getElementById(e.anchor)),

          //ignore if no element was found
          filter(el => !!el)
        )
        .subscribe(el => 
            document.scrollingElement
                 .scroll(
                     0, 
                     window.scrollY + el.getBoundingClientRect().top - (64 + 16)
                 )));

Additional improvements:

  • Instead of hardcoding the y-offset - one can query for the clientHeight of the mat-toobar and the clientTop of the element being scrolled to, and add them to get the offset
  • I have only tested this for scrolling to elements that are direct descendants of mat-sidenav-content. Maybe this logic can be extended to work for nested elements, nested routes etc etc etc

Upvotes: 1

gubo developer
gubo developer

Reputation: 1

is there a mat-sidenav-content solution for this ? as a workaround, i am subscribing to router events and looking at Scroll.anchor, then as per Using anchor link #id in Angular 6 i can affect a smooth scroll on view child ...

ex.

in html:

  <a routerLink="/menu" fragment="pizza">Pizza</a>
  ...
  <div #pizza>...</div>

in component:

    @ViewChild( 'pizza' ) pizza: ElementRef

    this.router.events.subscribe( (e:RouterEvent) => {
        if ( e instanceof Scroll ) {
          if ( e.anchor ==== 'pizza' ) {
            this.pizza.nativeElement.scrollIntoView( ... );
          }
        }
    } );

Upvotes: 0

Related Questions