From db61f29780f4c31028284033bdde66abedb5f5c1 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Wed, 13 Sep 2017 21:52:42 +0200 Subject: [PATCH] fix(drawer): drawer container not reacting to drawer removal and mode change * Fixes the drawer container not reacting if one of the drawers is destroyed. * Fixes the drawer container not reacting if the mode of a drawer is changed. Fixes #6271. --- src/lib/sidenav/drawer.spec.ts | 63 +++++++++++++++++++++++++++++++++- src/lib/sidenav/drawer.ts | 28 ++++++++++----- 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/src/lib/sidenav/drawer.spec.ts b/src/lib/sidenav/drawer.spec.ts index d858a6a2d8a1..c1a6a55aa86a 100644 --- a/src/lib/sidenav/drawer.spec.ts +++ b/src/lib/sidenav/drawer.spec.ts @@ -314,7 +314,11 @@ describe('MdDrawerContainer', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [MdSidenavModule, A11yModule, PlatformModule, NoopAnimationsModule], - declarations: [DrawerContainerTwoDrawerTestApp, DrawerDelayed], + declarations: [ + DrawerContainerTwoDrawerTestApp, + DrawerDelayed, + DrawerContainerStateChangesTestApp, + ], }); TestBed.compileComponents(); @@ -363,6 +367,47 @@ describe('MdDrawerContainer', () => { expect(parseInt(contentElement.style.marginLeft)).toBeGreaterThan(0); })); + + it('should recalculate the margin if a drawer is destroyed', fakeAsync(() => { + const fixture = TestBed.createComponent(DrawerContainerStateChangesTestApp); + + fixture.detectChanges(); + fixture.componentInstance.drawer.open(); + fixture.detectChanges(); + tick(); + fixture.detectChanges(); + + const contentElement = fixture.debugElement.nativeElement.querySelector('.mat-drawer-content'); + const initialMargin = parseInt(contentElement.style.marginLeft); + + expect(initialMargin).toBeGreaterThan(0); + + fixture.componentInstance.renderDrawer = false; + fixture.detectChanges(); + + expect(parseInt(contentElement.style.marginLeft)).toBeLessThan(initialMargin); + })); + + it('should recalculate the margin if the drawer mode is changed', fakeAsync(() => { + const fixture = TestBed.createComponent(DrawerContainerStateChangesTestApp); + + fixture.detectChanges(); + fixture.componentInstance.drawer.open(); + fixture.detectChanges(); + tick(); + fixture.detectChanges(); + + const contentElement = fixture.debugElement.nativeElement.querySelector('.mat-drawer-content'); + const initialMargin = parseInt(contentElement.style.marginLeft); + + expect(initialMargin).toBeGreaterThan(0); + + fixture.componentInstance.mode = 'over'; + fixture.detectChanges(); + + expect(parseInt(contentElement.style.marginLeft)).toBeLessThan(initialMargin); + })); + }); @@ -474,3 +519,19 @@ class DrawerDelayed { @ViewChild(MdDrawer) drawer: MdDrawer; showDrawer = false; } + + +@Component({ + template: ` + + + `, +}) +class DrawerContainerStateChangesTestApp { + @ViewChild(MdDrawer) drawer: MdDrawer; + @ViewChild(MdDrawerContainer) drawerContainer: MdDrawerContainer; + + mode = 'side'; + renderDrawer = true; +} + diff --git a/src/lib/sidenav/drawer.ts b/src/lib/sidenav/drawer.ts index 3d306303fac0..3fe2ef5244a9 100644 --- a/src/lib/sidenav/drawer.ts +++ b/src/lib/sidenav/drawer.ts @@ -398,8 +398,8 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy { private _left: MdDrawer | null; private _right: MdDrawer | null; - /** Subscription to the Directionality change EventEmitter. */ - private _dirChangeSubscription = Subscription.EMPTY; + /** Emits when the component is destroyed. */ + private _destroyed = new Subject(); _contentMargins = new Subject<{left: number, right: number}>(); @@ -409,23 +409,34 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy { // If a `Dir` directive exists up the tree, listen direction changes and update the left/right // properties to point to the proper start/end. if (_dir != null) { - this._dirChangeSubscription = _dir.change.subscribe(() => this._validateDrawers()); + takeUntil.call(_dir.change, this._destroyed).subscribe(() => this._validateDrawers()); } } ngAfterContentInit() { startWith.call(this._drawers.changes, null).subscribe(() => { this._validateDrawers(); + this._drawers.forEach((drawer: MdDrawer) => { this._watchDrawerToggle(drawer); this._watchDrawerPosition(drawer); this._watchDrawerMode(drawer); }); + + if (!this._drawers.length || + this._isDrawerOpen(this._start) || + this._isDrawerOpen(this._end) + ) { + this._updateContentMargins(); + } + + this._changeDetectorRef.markForCheck(); }); } ngOnDestroy() { - this._dirChangeSubscription.unsubscribe(); + this._destroyed.next(); + this._destroyed.complete(); } /** Calls `open` of both start and end drawers */ @@ -478,10 +489,11 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy { /** Subscribes to changes in drawer mode so we can run change detection. */ private _watchDrawerMode(drawer: MdDrawer): void { if (drawer) { - takeUntil.call(drawer._modeChanged, this._drawers.changes).subscribe(() => { - this._updateContentMargins(); - this._changeDetectorRef.markForCheck(); - }); + takeUntil.call(drawer._modeChanged, merge(this._drawers.changes, this._destroyed)) + .subscribe(() => { + this._updateContentMargins(); + this._changeDetectorRef.markForCheck(); + }); } }