Skip to content

Commit 441c98e

Browse files
crisbetommalerba
authored andcommitted
fix(sidenav): scrollable instance not exposed when explicitly specifying content element (#11706)
This is a resubmit of #11517 which got in by accident. * Fixes the `MatSidenavContainer.scrollable` being undefined if the consumer has set the `mat-sidenav-content` themselves. The issue comes from the fact that we only query for scrollables inside the drawer's own view, but not inside the projected content. * Fixes the example in the sidenav docs accessing the scrollable too early. Fixes #10884. BREAKING CHANGE: the constructor signature of the `MatDrawerContent` and `MatSidenavContent` has changed.
1 parent e462f3d commit 441c98e

File tree

5 files changed

+60
-11
lines changed

5 files changed

+60
-11
lines changed

src/lib/sidenav/drawer-container.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55

66
<ng-content select="mat-drawer-content">
77
</ng-content>
8-
<mat-drawer-content *ngIf="!_content" cdkScrollable>
8+
<mat-drawer-content *ngIf="!_content">
99
<ng-content></ng-content>
1010
</mat-drawer-content>

src/lib/sidenav/drawer.spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {A11yModule} from '@angular/cdk/a11y';
1616
import {PlatformModule} from '@angular/cdk/platform';
1717
import {ESCAPE} from '@angular/cdk/keycodes';
1818
import {dispatchKeyboardEvent} from '@angular/cdk/testing';
19+
import {CdkScrollable} from '@angular/cdk/scrolling';
1920

2021

2122
describe('MatDrawer', () => {
@@ -497,6 +498,7 @@ describe('MatDrawerContainer', () => {
497498
DrawerContainerStateChangesTestApp,
498499
AutosizeDrawer,
499500
BasicTestApp,
501+
DrawerContainerWithContent,
500502
],
501503
});
502504

@@ -719,6 +721,27 @@ describe('MatDrawerContainer', () => {
719721
expect(fixture.componentInstance.drawer.opened).toBe(false);
720722
}));
721723

724+
it('should expose a scrollable when the consumer has not specified drawer content',
725+
fakeAsync(() => {
726+
const fixture = TestBed.createComponent(DrawerContainerTwoDrawerTestApp);
727+
728+
fixture.detectChanges();
729+
730+
expect(fixture.componentInstance.drawerContainer.scrollable instanceof CdkScrollable)
731+
.toBe(true);
732+
}));
733+
734+
it('should expose a scrollable when the consumer has specified drawer content',
735+
fakeAsync(() => {
736+
const fixture = TestBed.createComponent(DrawerContainerWithContent);
737+
738+
fixture.detectChanges();
739+
740+
expect(fixture.componentInstance.drawerContainer.scrollable instanceof CdkScrollable)
741+
.toBe(true);
742+
}));
743+
744+
722745
});
723746

724747

@@ -901,3 +924,16 @@ class AutosizeDrawer {
901924
@ViewChild(MatDrawer) drawer: MatDrawer;
902925
fillerWidth = 0;
903926
}
927+
928+
929+
@Component({
930+
template: `
931+
<mat-drawer-container>
932+
<mat-drawer>Drawer</mat-drawer>
933+
<mat-drawer-content>Content</mat-drawer-content>
934+
</mat-drawer-container>
935+
`,
936+
})
937+
class DrawerContainerWithContent {
938+
@ViewChild(MatDrawerContainer) drawerContainer: MatDrawerContainer;
939+
}

src/lib/sidenav/drawer.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {Directionality} from '@angular/cdk/bidi';
1111
import {coerceBooleanProperty} from '@angular/cdk/coercion';
1212
import {ESCAPE} from '@angular/cdk/keycodes';
1313
import {Platform} from '@angular/cdk/platform';
14-
import {CdkScrollable} from '@angular/cdk/scrolling';
14+
import {CdkScrollable, ScrollDispatcher} from '@angular/cdk/scrolling';
1515
import {DOCUMENT} from '@angular/common';
1616
import {
1717
AfterContentChecked,
@@ -75,10 +75,14 @@ export function MAT_DRAWER_DEFAULT_AUTOSIZE_FACTORY(): boolean {
7575
changeDetection: ChangeDetectionStrategy.OnPush,
7676
encapsulation: ViewEncapsulation.None,
7777
})
78-
export class MatDrawerContent implements AfterContentInit {
78+
export class MatDrawerContent extends CdkScrollable implements AfterContentInit {
7979
constructor(
8080
private _changeDetectorRef: ChangeDetectorRef,
81-
@Inject(forwardRef(() => MatDrawerContainer)) public _container: MatDrawerContainer) {
81+
@Inject(forwardRef(() => MatDrawerContainer)) public _container: MatDrawerContainer,
82+
elementRef: ElementRef<HTMLElement>,
83+
scrollDispatcher: ScrollDispatcher,
84+
ngZone: NgZone) {
85+
super(elementRef, scrollDispatcher, ngZone);
8286
}
8387

8488
ngAfterContentInit() {
@@ -401,6 +405,7 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
401405
export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy {
402406
@ContentChildren(MatDrawer) _drawers: QueryList<MatDrawer>;
403407
@ContentChild(MatDrawerContent) _content: MatDrawerContent;
408+
@ViewChild(MatDrawerContent) _userContent: MatDrawerContent;
404409

405410
/** The drawer child with the `start` position. */
406411
get start(): MatDrawer | null { return this._start; }
@@ -471,7 +476,9 @@ export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy
471476
readonly _contentMarginChanges = new Subject<{left: number|null, right: number|null}>();
472477

473478
/** Reference to the CdkScrollable instance that wraps the scrollable content. */
474-
@ViewChild(CdkScrollable) scrollable: CdkScrollable;
479+
get scrollable(): CdkScrollable {
480+
return this._userContent || this._content;
481+
}
475482

476483
constructor(@Optional() private _dir: Directionality,
477484
private _element: ElementRef,

src/lib/sidenav/sidenav.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ The `<mat-sidenav>` can render in one of three different ways based on the `mode
109109

110110
| Mode | Description |
111111
|--------|-----------------------------------------------------------------------------------------|
112-
| `over` | Sidenav floats over the primary content, which is covered by a backdrop |
113-
| `push` | Sidenav pushes the primary content out of its way, also covering it with a backdrop |
112+
| `over` | Sidenav floats over the primary content, which is covered by a backdrop |
113+
| `push` | Sidenav pushes the primary content out of its way, also covering it with a backdrop |
114114
| `side` | Sidenav appears side-by-side with the main content, shrinking the main content's width to make space for the sidenav. |
115115

116116
If no `mode` is specified, `over` is used by default.
@@ -186,10 +186,10 @@ To react to scrolling inside the `<mat-sidenav-container>`, you can get a hold o
186186
`CdkScrollable` instance through the `MatSidenavContainer`.
187187

188188
```ts
189-
class YourComponent {
189+
class YourComponent implements AfterViewInit {
190190
@ViewChild(MatSidenavContainer) sidenavContainer: MatSidenavContainer;
191191

192-
constructor() {
192+
ngAfterViewInit() {
193193
this.sidenavContainer.scrollable.elementScrolled().subscribe(() => /* react to scrolling */);
194194
}
195195
}

src/lib/sidenav/sidenav.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@ import {
1717
Input,
1818
ViewEncapsulation,
1919
QueryList,
20+
ElementRef,
21+
NgZone,
2022
} from '@angular/core';
2123
import {MatDrawer, MatDrawerContainer, MatDrawerContent} from './drawer';
2224
import {matDrawerAnimations} from './drawer-animations';
2325
import {coerceBooleanProperty, coerceNumberProperty} from '@angular/cdk/coercion';
26+
import {ScrollDispatcher} from '@angular/cdk/scrolling';
2427

2528

2629
@Component({
@@ -38,8 +41,11 @@ import {coerceBooleanProperty, coerceNumberProperty} from '@angular/cdk/coercion
3841
export class MatSidenavContent extends MatDrawerContent {
3942
constructor(
4043
changeDetectorRef: ChangeDetectorRef,
41-
@Inject(forwardRef(() => MatSidenavContainer)) container: MatSidenavContainer) {
42-
super(changeDetectorRef, container);
44+
@Inject(forwardRef(() => MatSidenavContainer)) container: MatSidenavContainer,
45+
elementRef: ElementRef<HTMLElement>,
46+
scrollDispatcher: ScrollDispatcher,
47+
ngZone: NgZone) {
48+
super(changeDetectorRef, container, elementRef, scrollDispatcher, ngZone);
4349
}
4450
}
4551

0 commit comments

Comments
 (0)