问题
The Angular Material CDK provides a Directive CdkScrollable, which allows you to listen to ScrollEvents of a specific container.
I am now trying to access the CdkScrollable of the MatSidenavContent, which is added by default.
However my @ViewChild(CdkScrollable) and @ContentChild(CdkScrollable) are always undefined.
My Component looks something like this:
<mat-sidenav-container>
<mat-sidenav>Sidenav content</mat-sidenav>
<div>Main content</div>
</mat-sidenav-container>
The resulting DOM looks something like this:
<mat-sidenav-container>
<div class="mat-drawer-backdrop"></div>
<div tabindex="-1" class="cdk-visually-hidden cdk-focus-trap-anchor"></div>
<mat-sidenav>Sidenav content</mat-sidenav>
<mat-sidenav-content cdkScrollable>
<div>Main content</div>
</mat-sidenav-content>
</mat-sidenav-container>
The mat-sidenav-content Component, which is generated automatically, uses a CdkScrollable-Directive, which I need to access.
My question is now:
Is it possible to access that Directive and if so, how?
回答1:
- Add to your app module imports: ScrollDispatchModule.
- Add cdkScrollable to your mat-sidenav-content:
<mat-sidenav-content cdkScrollable> </mat-sidenav-content>
- In your root component:
a) inject ScrollDispatcher from @angular/cdk/overlay and subscribe to scrolling:
constructor(public scroll: ScrollDispatcher) {
this.scrollingSubscription = this.scroll
.scrolled()
.subscribe((data: CdkScrollable) => {
this.onWindowScroll(data);
});
}
c) do something when scrolling, e.g. check the offset
private onWindowScroll(data: CdkScrollable) {
const scrollTop = data.getElementRef().nativeElement.scrollTop || 0;
if (this.lastOffset > scrollTop) {
// console.log('Show toolbar');
} else if (scrollTop < 10) {
// console.log('Show toolbar');
} else if (scrollTop > 100) {
// console.log('Hide toolbar');
}
this.lastOffset = scrollTop;
}
Documentation: https://material.angular.io/cdk/scrolling/api
回答2:
I opened an Issue on @angular/material some time ago and they now expose the CdkScrollable-Instance.
To use it, you need to access the MatSidenavContainer using @ViewChild(MatSidenavContainer. This instance has a public member scrollable, which is the CdkScrollable instance.
An example can be found here
Edit: As the example is not very complete and a few people are having difficulties implementing it, I'll write my own example here:
HTML:
<mat-sidenav-container>
<mat-sidenav #sidenav>
Sidenav Content
</mat-sidenav>
<div>
Main Content
</div>
</mat-sidenav-container>
TypeScript:
import { Component, AfterViewInit, ViewChild } from '@angular/core';
import { MatSidenavContainer } from '@angular/material';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements AfterViewInit {
@ViewChild(MatSidenavContainer) sidenavContainer: MatSidenavContainer;
constructor() {
}
ngAfterViewInit() {
console.log(this.sidenavContainer.scrollable);
}
}
Important:
- Don't use
<mat-sidenav-content>. This tag is generated automatically and it has thecdkScrollabledirective attached to it. If you use<mat-sidenav-content>in your own template, thescrollablewill be undefined. - Use
AfterViewInitinstead ofOnInit. As much as I know,@ViewChildis resolved inAfterViewInit,OnInitis probably too early.
来源:https://stackoverflow.com/questions/47528852/angular-material-sidenav-cdkscrollable