Skip to content

Commit e5c6ce2

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 e5c6ce2

File tree

2 files changed

+100
-6
lines changed

2 files changed

+100
-6
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 & 5 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';
@@ -32,6 +34,7 @@ import {first, takeUntil, startWith} from '../core/rxjs/index';
3234
import {DOCUMENT} from '@angular/platform-browser';
3335
import {merge} from 'rxjs/observable/merge';
3436
import {Subscription} from 'rxjs/Subscription';
37+
import {Subject} from 'rxjs/Subject';
3538

3639

3740
/** Throws an exception when two MdDrawer are matching the same position. */
@@ -90,7 +93,7 @@ export class MdDrawerToggleResult {
9093
changeDetection: ChangeDetectionStrategy.OnPush,
9194
encapsulation: ViewEncapsulation.None,
9295
})
93-
export class MdDrawer implements AfterContentInit, OnDestroy {
96+
export class MdDrawer implements AfterContentInit, OnDestroy, OnChanges {
9497
private _focusTrap: FocusTrap;
9598
private _elementFocusedBeforeDrawerWasOpened: HTMLElement | null = null;
9699

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

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

@@ -206,6 +212,12 @@ export class MdDrawer implements AfterContentInit, OnDestroy {
206212
}
207213
}
208214

215+
ngOnChanges(changes: SimpleChanges) {
216+
if (changes.mode) {
217+
this.onModeChanged.emit();
218+
}
219+
}
220+
209221
/**
210222
* Whether the drawer is opened. We overload this because we trigger an event when it
211223
* starts or end.
@@ -339,8 +351,8 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy {
339351
private _left: MdDrawer | null;
340352
private _right: MdDrawer | null;
341353

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

345357
/** Inline styles to be applied to the container. */
346358
_styles: { marginLeft: string; marginRight: string; transform: string; };
@@ -351,22 +363,35 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy {
351363
// If a `Dir` directive exists up the tree, listen direction changes and update the left/right
352364
// properties to point to the proper start/end.
353365
if (_dir != null) {
354-
this._dirChangeSubscription = _dir.change.subscribe(() => this._validateDrawers());
366+
367+
takeUntil.call(_dir.change, this._onDestroy).subscribe(() => this._validateDrawers());
355368
}
356369
}
357370

358371
ngAfterContentInit() {
359372
startWith.call(this._drawers.changes, null).subscribe(() => {
360373
this._validateDrawers();
374+
361375
this._drawers.forEach((drawer: MdDrawer) => {
362376
this._watchDrawerToggle(drawer);
363377
this._watchDrawerPosition(drawer);
378+
this._watchDrawerMode(drawer);
364379
});
380+
381+
if (!this._drawers.length ||
382+
this._isDrawerOpen(this._start) ||
383+
this._isDrawerOpen(this._end)
384+
) {
385+
this._updateStyles();
386+
}
387+
388+
this._changeDetectorRef.markForCheck();
365389
});
366390
}
367391

368392
ngOnDestroy() {
369-
this._dirChangeSubscription.unsubscribe();
393+
this._onDestroy.next();
394+
this._onDestroy.complete();
370395
}
371396

372397
/** Calls `open` of both start and end drawers */
@@ -416,6 +441,14 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy {
416441
});
417442
}
418443

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

0 commit comments

Comments
 (0)