Skip to content

Commit faabcd1

Browse files
committed
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.
1 parent e4d48d7 commit faabcd1

File tree

2 files changed

+100
-7
lines changed

2 files changed

+100
-7
lines changed

src/lib/sidenav/drawer.spec.ts

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,11 @@ describe('MdDrawerContainer', () => {
312312
beforeEach(async(() => {
313313
TestBed.configureTestingModule({
314314
imports: [MdSidenavModule, A11yModule, PlatformModule, NoopAnimationsModule],
315-
declarations: [DrawerContainerTwoDrawerTestApp, DrawerDelayed],
315+
declarations: [
316+
DrawerContainerTwoDrawerTestApp,
317+
DrawerDelayed,
318+
DrawerContainerStateChangesTestApp,
319+
],
316320
});
317321

318322
TestBed.compileComponents();
@@ -361,6 +365,47 @@ describe('MdDrawerContainer', () => {
361365

362366
expect(parseInt(contentElement.style.marginLeft)).toBeGreaterThan(0);
363367
}));
368+
369+
it('should recalculate the margin if a drawer is destroyed', fakeAsync(() => {
370+
const fixture = TestBed.createComponent(DrawerContainerStateChangesTestApp);
371+
372+
fixture.detectChanges();
373+
fixture.componentInstance.drawer.open();
374+
fixture.detectChanges();
375+
tick();
376+
fixture.detectChanges();
377+
378+
const contentElement = fixture.debugElement.nativeElement.querySelector('.mat-drawer-content');
379+
const initialMargin = parseInt(contentElement.style.marginLeft);
380+
381+
expect(initialMargin).toBeGreaterThan(0);
382+
383+
fixture.componentInstance.renderDrawer = false;
384+
fixture.detectChanges();
385+
386+
expect(parseInt(contentElement.style.marginLeft)).toBeLessThan(initialMargin);
387+
}));
388+
389+
it('should recalculate the margin if the drawer mode is changed', fakeAsync(() => {
390+
const fixture = TestBed.createComponent(DrawerContainerStateChangesTestApp);
391+
392+
fixture.detectChanges();
393+
fixture.componentInstance.drawer.open();
394+
fixture.detectChanges();
395+
tick();
396+
fixture.detectChanges();
397+
398+
const contentElement = fixture.debugElement.nativeElement.querySelector('.mat-drawer-content');
399+
const initialMargin = parseInt(contentElement.style.marginLeft);
400+
401+
expect(initialMargin).toBeGreaterThan(0);
402+
403+
fixture.componentInstance.mode = 'over';
404+
fixture.detectChanges();
405+
406+
expect(parseInt(contentElement.style.marginLeft)).toBeLessThan(initialMargin);
407+
}));
408+
364409
});
365410

366411

@@ -472,3 +517,19 @@ class DrawerDelayed {
472517
@ViewChild(MdDrawer) drawer: MdDrawer;
473518
showDrawer = false;
474519
}
520+
521+
522+
@Component({
523+
template: `
524+
<md-drawer-container>
525+
<md-drawer *ngIf="renderDrawer" [mode]="mode"></md-drawer>
526+
</md-drawer-container>`,
527+
})
528+
class DrawerContainerStateChangesTestApp {
529+
@ViewChild(MdDrawer) drawer: MdDrawer;
530+
@ViewChild(MdDrawerContainer) drawerContainer: MdDrawerContainer;
531+
532+
mode = 'side';
533+
renderDrawer = true;
534+
}
535+

src/lib/sidenav/drawer.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import {
2323
OnDestroy,
2424
Inject,
2525
ChangeDetectorRef,
26+
OnChanges,
27+
SimpleChanges,
2628
} from '@angular/core';
2729
import {animate, state, style, transition, trigger, AnimationEvent} from '@angular/animations';
2830
import {Directionality, coerceBooleanProperty} from '../core';
@@ -31,7 +33,7 @@ import {ESCAPE} from '../core/keyboard/keycodes';
3133
import {first, takeUntil, startWith} from '../core/rxjs/index';
3234
import {DOCUMENT} from '@angular/platform-browser';
3335
import {merge} from 'rxjs/observable/merge';
34-
import {Subscription} from 'rxjs/Subscription';
36+
import {Subject} from 'rxjs/Subject';
3537

3638

3739
/** Throws an exception when two MdDrawer are matching the same position. */
@@ -90,7 +92,7 @@ export class MdDrawerToggleResult {
9092
changeDetection: ChangeDetectionStrategy.OnPush,
9193
encapsulation: ViewEncapsulation.None,
9294
})
93-
export class MdDrawer implements AfterContentInit, OnDestroy {
95+
export class MdDrawer implements AfterContentInit, OnDestroy, OnChanges {
9496
private _focusTrap: FocusTrap;
9597
private _elementFocusedBeforeDrawerWasOpened: HTMLElement | null = null;
9698

@@ -153,6 +155,9 @@ export class MdDrawer implements AfterContentInit, OnDestroy {
153155
/** Event emitted when the drawer's position changes. */
154156
@Output('positionChanged') onPositionChanged = new EventEmitter<void>();
155157

158+
/** Event emitted when the drawer's mode changes. */
159+
@Output('modeChanged') onModeChanged = new EventEmitter<void>();
160+
156161
/** @deprecated */
157162
@Output('align-changed') onAlignChanged = new EventEmitter<void>();
158163

@@ -206,6 +211,12 @@ export class MdDrawer implements AfterContentInit, OnDestroy {
206211
}
207212
}
208213

214+
ngOnChanges(changes: SimpleChanges) {
215+
if (changes.mode) {
216+
this.onModeChanged.emit();
217+
}
218+
}
219+
209220
/**
210221
* Whether the drawer is opened. We overload this because we trigger an event when it
211222
* starts or end.
@@ -339,8 +350,8 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy {
339350
private _left: MdDrawer | null;
340351
private _right: MdDrawer | null;
341352

342-
/** Subscription to the Directionality change EventEmitter. */
343-
private _dirChangeSubscription = Subscription.EMPTY;
353+
/** Emits when the component is destroyed. */
354+
private _onDestroy = new Subject<void>();
344355

345356
/** Inline styles to be applied to the container. */
346357
_styles: { marginLeft: string; marginRight: string; transform: string; };
@@ -351,22 +362,35 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy {
351362
// If a `Dir` directive exists up the tree, listen direction changes and update the left/right
352363
// properties to point to the proper start/end.
353364
if (_dir != null) {
354-
this._dirChangeSubscription = _dir.change.subscribe(() => this._validateDrawers());
365+
366+
takeUntil.call(_dir.change, this._onDestroy).subscribe(() => this._validateDrawers());
355367
}
356368
}
357369

358370
ngAfterContentInit() {
359371
startWith.call(this._drawers.changes, null).subscribe(() => {
360372
this._validateDrawers();
373+
361374
this._drawers.forEach((drawer: MdDrawer) => {
362375
this._watchDrawerToggle(drawer);
363376
this._watchDrawerPosition(drawer);
377+
this._watchDrawerMode(drawer);
364378
});
379+
380+
if (!this._drawers.length ||
381+
this._isDrawerOpen(this._start) ||
382+
this._isDrawerOpen(this._end)
383+
) {
384+
this._updateStyles();
385+
}
386+
387+
this._changeDetectorRef.markForCheck();
365388
});
366389
}
367390

368391
ngOnDestroy() {
369-
this._dirChangeSubscription.unsubscribe();
392+
this._onDestroy.next();
393+
this._onDestroy.complete();
370394
}
371395

372396
/** Calls `open` of both start and end drawers */
@@ -416,6 +440,14 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy {
416440
});
417441
}
418442

443+
private _watchDrawerMode(drawer: MdDrawer): void {
444+
takeUntil.call(drawer.onModeChanged, merge(this._drawers.changes, this._onDestroy))
445+
.subscribe(() => {
446+
this._updateStyles();
447+
this._changeDetectorRef.markForCheck();
448+
});
449+
}
450+
419451
/** Toggles the 'mat-drawer-opened' class on the main 'md-drawer-container' element. */
420452
private _setContainerClass(isAdd: boolean): void {
421453
if (isAdd) {

0 commit comments

Comments
 (0)