Skip to content

Commit 19243a8

Browse files
committed
fix(sidenav): container not picking up indirect descendant sidenavs
Fixes the sidenav container not picking up indirect descendant sidenavs.
1 parent ef92091 commit 19243a8

File tree

5 files changed

+91
-16
lines changed

5 files changed

+91
-16
lines changed

src/material/sidenav/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ ng_test_library(
6565
"//src/cdk/platform",
6666
"//src/cdk/scrolling",
6767
"//src/cdk/testing",
68+
"@npm//@angular/common",
6869
"@npm//@angular/platform-browser",
6970
],
7071
)

src/material/sidenav/drawer.spec.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ import {PlatformModule, Platform} from '@angular/cdk/platform';
1818
import {ESCAPE} from '@angular/cdk/keycodes';
1919
import {dispatchKeyboardEvent, createKeyboardEvent, dispatchEvent} from '@angular/cdk/testing';
2020
import {CdkScrollable} from '@angular/cdk/scrolling';
21+
import {CommonModule} from '@angular/common';
2122

2223

2324
describe('MatDrawer', () => {
2425
beforeEach(async(() => {
2526
TestBed.configureTestingModule({
26-
imports: [MatSidenavModule, A11yModule, PlatformModule, NoopAnimationsModule],
27+
imports: [MatSidenavModule, A11yModule, PlatformModule, NoopAnimationsModule, CommonModule],
2728
declarations: [
2829
BasicTestApp,
2930
DrawerContainerNoDrawerTestApp,
@@ -33,6 +34,7 @@ describe('MatDrawer', () => {
3334
DrawerWithFocusableElements,
3435
DrawerOpenBinding,
3536
DrawerWithoutFocusableElements,
37+
IndirectDescendantDrawer,
3638
],
3739
});
3840

@@ -323,6 +325,21 @@ describe('MatDrawer', () => {
323325
expect(document.activeElement)
324326
.toBe(closeButton, 'Expected focus not to be restored to the open button on close.');
325327
}));
328+
329+
it('should pick up drawers that are not direct descendants', fakeAsync(() => {
330+
const fixture = TestBed.createComponent(IndirectDescendantDrawer);
331+
fixture.detectChanges();
332+
333+
expect(fixture.componentInstance.drawer.opened).toBe(false);
334+
335+
fixture.componentInstance.container.open();
336+
fixture.detectChanges();
337+
tick();
338+
fixture.detectChanges();
339+
340+
expect(fixture.componentInstance.drawer.opened).toBe(true);
341+
}));
342+
326343
});
327344

328345
describe('attributes', () => {
@@ -998,3 +1015,19 @@ class AutosizeDrawer {
9981015
class DrawerContainerWithContent {
9991016
@ViewChild(MatDrawerContainer, {static: false}) drawerContainer: MatDrawerContainer;
10001017
}
1018+
1019+
1020+
@Component({
1021+
// Note that we need the `ng-container` with the `ngSwitch` so that
1022+
// there's a directive between the container and the drawer.
1023+
template: `
1024+
<mat-drawer-container #container>
1025+
<ng-container [ngSwitch]="true">
1026+
<mat-drawer #drawer>Drawer</mat-drawer>
1027+
</ng-container>
1028+
</mat-drawer-container>`,
1029+
})
1030+
class IndirectDescendantDrawer {
1031+
@ViewChild('container', {static: false}) container: MatDrawerContainer;
1032+
@ViewChild('drawer', {static: false}) drawer: MatDrawer;
1033+
}

src/material/sidenav/drawer.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,11 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
461461
encapsulation: ViewEncapsulation.None,
462462
})
463463
export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy {
464-
@ContentChildren(MatDrawer) _drawers: QueryList<MatDrawer>;
464+
@ContentChildren(MatDrawer, {
465+
// We need to use `descendants: true`, because Ivy will no longer match
466+
// indirect descendants if it's left as false.
467+
descendants: true
468+
}) _drawers: QueryList<MatDrawer>;
465469
@ContentChild(MatDrawerContent, {static: false}) _content: MatDrawerContent;
466470
@ViewChild(MatDrawerContent, {static: false}) _userContent: MatDrawerContent;
467471

src/material/sidenav/sidenav.spec.ts

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
1-
import {Component} from '@angular/core';
2-
import {async, TestBed, ComponentFixture} from '@angular/core/testing';
3-
import {MatSidenav, MatSidenavModule} from './index';
1+
import {Component, ViewChild} from '@angular/core';
2+
import {async, TestBed, fakeAsync, tick} from '@angular/core/testing';
3+
import {MatSidenav, MatSidenavModule, MatSidenavContainer} from './index';
44
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
55
import {By} from '@angular/platform-browser';
6+
import {CommonModule} from '@angular/common';
67

78

89
describe('MatSidenav', () => {
9-
let fixture: ComponentFixture<SidenavWithFixedPosition>;
10-
let sidenavEl: HTMLElement;
11-
1210
beforeEach(async(() => {
1311
TestBed.configureTestingModule({
14-
imports: [MatSidenavModule, NoopAnimationsModule],
15-
declarations: [SidenavWithFixedPosition],
12+
imports: [MatSidenavModule, NoopAnimationsModule, CommonModule],
13+
declarations: [SidenavWithFixedPosition, IndirectDescendantSidenav],
1614
});
1715

1816
TestBed.compileComponents();
19-
20-
fixture = TestBed.createComponent(SidenavWithFixedPosition);
21-
fixture.detectChanges();
22-
23-
sidenavEl = fixture.debugElement.query(By.directive(MatSidenav))!.nativeElement;
2417
}));
2518

2619
it('should be fixed position when in fixed mode', () => {
20+
const fixture = TestBed.createComponent(SidenavWithFixedPosition);
21+
fixture.detectChanges();
22+
const sidenavEl = fixture.debugElement.query(By.directive(MatSidenav))!.nativeElement;
23+
2724
expect(sidenavEl.classList).toContain('mat-sidenav-fixed');
2825

2926
fixture.componentInstance.fixed = false;
@@ -33,6 +30,10 @@ describe('MatSidenav', () => {
3330
});
3431

3532
it('should set fixed bottom and top when in fixed mode', () => {
33+
const fixture = TestBed.createComponent(SidenavWithFixedPosition);
34+
fixture.detectChanges();
35+
const sidenavEl = fixture.debugElement.query(By.directive(MatSidenav))!.nativeElement;
36+
3637
expect(sidenavEl.style.top).toBe('20px');
3738
expect(sidenavEl.style.bottom).toBe('30px');
3839

@@ -42,6 +43,21 @@ describe('MatSidenav', () => {
4243
expect(sidenavEl.style.top).toBeFalsy();
4344
expect(sidenavEl.style.bottom).toBeFalsy();
4445
});
46+
47+
it('should pick up sidenavs that are not direct descendants', fakeAsync(() => {
48+
const fixture = TestBed.createComponent(IndirectDescendantSidenav);
49+
fixture.detectChanges();
50+
51+
expect(fixture.componentInstance.sidenav.opened).toBe(false);
52+
53+
fixture.componentInstance.container.open();
54+
fixture.detectChanges();
55+
tick();
56+
fixture.detectChanges();
57+
58+
expect(fixture.componentInstance.sidenav.opened).toBe(true);
59+
}));
60+
4561
});
4662

4763

@@ -65,3 +81,20 @@ class SidenavWithFixedPosition {
6581
fixedTop = 20;
6682
fixedBottom = 30;
6783
}
84+
85+
86+
@Component({
87+
// Note that we need the `ng-container` with the `ngSwitch` so that
88+
// there's a directive between the container and the sidenav.
89+
template: `
90+
<mat-sidenav-container #container>
91+
<ng-container [ngSwitch]="true">
92+
<mat-sidenav #sidenav>Sidenav.</mat-sidenav>
93+
</ng-container>
94+
<mat-sidenav-content>Some content.</mat-sidenav-content>
95+
</mat-sidenav-container>`,
96+
})
97+
class IndirectDescendantSidenav {
98+
@ViewChild('container', {static: false}) container: MatSidenavContainer;
99+
@ViewChild('sidenav', {static: false}) sidenav: MatSidenav;
100+
}

src/material/sidenav/sidenav.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ export class MatSidenav extends MatDrawer {
114114
encapsulation: ViewEncapsulation.None,
115115
})
116116
export class MatSidenavContainer extends MatDrawerContainer {
117-
@ContentChildren(MatSidenav) _drawers: QueryList<MatSidenav>;
117+
@ContentChildren(MatSidenav, {
118+
// We need to use `descendants: true`, because Ivy will no longer match
119+
// indirect descendants if it's left as false.
120+
descendants: true
121+
}) _drawers: QueryList<MatSidenav>;
118122
@ContentChild(MatSidenavContent, {static: false}) _content: MatSidenavContent;
119123
}

0 commit comments

Comments
 (0)