Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect scroll events in mat-sidenav-container

I can't figure out how to detect when the mat-sidenav-container scrolls in angular material 2.

I would like to call a method on my component when a user scrolls. However when using the sidenav-container the scroll event is no longer fired on the window.

Instead an extra <mat-sidenav-content cdkscrollable></mat-sidenav-content> element is added and this is where the scroll bars are. How can I detect when scrolling occurs on this component if I can't directly access it to put an (scroll)="myMethod()" event listener on it.

Any ideas?

like image 407
Chris Avatar asked Oct 29 '17 01:10

Chris


4 Answers

Instead of calling a method on every scroll event you could create an Observable of scroll events and subscribe to it.

Using Observable

enum Direction {
    Up = 'Up',
    Down = 'Down'
}

ngAfterViewInit() {
    const content = document.querySelector('.mat-sidenav-content');
    const scroll$ = fromEvent(content, 'scroll').pipe(
      throttleTime(10), // only emit every 10 ms
      map(() => content.scrollTop), // get vertical scroll position
      pairwise(), // look at this and the last emitted element
      map(([y1, y2]): Direction => (y2 < y1 ? Direction.Up : Direction.Down)), // compare this and the last element to figure out scrolling direction
      distinctUntilChanged(), // only emit when scrolling direction changed
      share(), // share a single subscription to the underlying sequence in case of multiple subscribers
    );

    const goingUp$ = scroll$.pipe(
      filter(direction => direction === Direction.Up)
    );

    const goingDown$ = scroll$.pipe(
      filter(direction => direction === Direction.Down)
    );

    goingUp$.subscribe(() => console.log('scrolling up');
    goingDown$.subscribe(() => console.log('scrolling down');
}

For further explanation of the code above check out: https://netbasal.com/reactive-sticky-header-in-angular-12dbffb3f1d3

like image 166
frido Avatar answered Nov 14 '22 20:11

frido


My current Version Angular 8
Solution 1:

  • Check if you content is placed inside the

        <mat-sidenav-container fullscreen> </mat-sidenav-container>
    
  • With fullscreen property above any of the window methods like window.scroll() and the properties like window.pageYOffset will not work

  • Remove fullscreen and try. It will workstrong text

Solution 2: You want to keep the property fullscreen

  • Check if you content is placed inside the

       <mat-sidenav-container fullscreen>
          <mat-sidenav></mat-sidenav> 
          <div>
             //your content
          </div>
       </mat-sidenav-container>
    
  • In above i did't put my content inside a mat-sidenav-content like below, since angular places it for you by default inside a mat-sidenav-content tag gives us the benefit of default behaviour

        <mat-sidenav-content>
           <div>
             //your content
          </div>
        </mat-sidenav-content>
    
  • import {MatSidenavModule} from '@angular/material/sidenav'; in app.module.ts and declare in imports array.

  • In your component in which you would like to get scroll event to do some stuff when the scroll position changes. Do the following

    import { Component, NgZone , OnInit } from '@angular/core';
    import { ScrollDispatcher } from '@angular/cdk/scrolling';
    import { CdkScrollable } from '@angular/cdk/scrolling';
    @Component({
      selector: 'app-scroll-top',
      templateUrl: './scroll-top.component.html',
      styleUrls: ['./scroll-top.component.css']
    })
    export class ExampleComponent implements OnInit {


      constructor (private scrollDispatcher: ScrollDispatcher, private zone: NgZone) {}

      ngOnInit() {
      }

      ngAfterViewInit() {
        this.scrollDispatcher.scrolled().
        subscribe((cdk: CdkScrollable)  => {
        this.zone.run(() => {
        //Here you can add what to happen when scroll changed
        //I want to display the scroll position for example
          const scrollPosition = cdk.getElementRef().nativeElement.scrollTop;
          console.log(scrollPosition);
        });
        });
      }
like image 43
Guru Cse Avatar answered Nov 14 '22 20:11

Guru Cse


Could you show me your css file? I also experienced the same problem, but due to the following css being applied to mat-sidenav-container.

height: 100vh;
like image 1
Daiki Ojima Avatar answered Nov 14 '22 22:11

Daiki Ojima


Rather than letting Angular automatically insert the tag, include the side-nav-content tag in your HTML. Then you can add the listener to it.

<mat-sidenav-container>
  <mat-sidenav>
  </mat-sidenav>
  <mat-sidenav-content (scroll)="myScrollHandler($event)">
  </mat-sidenav-content>
</mat-sidenav-container>
like image 1
jm22 Avatar answered Nov 14 '22 20:11

jm22