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?
Instead of calling a method on every scroll event you could create an Observable of scroll events and subscribe to it.
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
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
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);
});
});
}
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;
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>
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