Skip to content

Commit

Permalink
fix(drawer): drawer container not reacting to drawer removal and mode…
Browse files Browse the repository at this point in the history
… 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.
  • Loading branch information
crisbeto committed Sep 13, 2017
1 parent e4d48d7 commit d816484
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 7 deletions.
63 changes: 62 additions & 1 deletion src/lib/sidenav/drawer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,11 @@ describe('MdDrawerContainer', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MdSidenavModule, A11yModule, PlatformModule, NoopAnimationsModule],
declarations: [DrawerContainerTwoDrawerTestApp, DrawerDelayed],
declarations: [
DrawerContainerTwoDrawerTestApp,
DrawerDelayed,
DrawerContainerStateChangesTestApp,
],
});

TestBed.compileComponents();
Expand Down Expand Up @@ -361,6 +365,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);
}));

});


Expand Down Expand Up @@ -472,3 +517,19 @@ class DrawerDelayed {
@ViewChild(MdDrawer) drawer: MdDrawer;
showDrawer = false;
}


@Component({
template: `
<md-drawer-container>
<md-drawer *ngIf="renderDrawer" [mode]="mode"></md-drawer>
</md-drawer-container>`,
})
class DrawerContainerStateChangesTestApp {
@ViewChild(MdDrawer) drawer: MdDrawer;
@ViewChild(MdDrawerContainer) drawerContainer: MdDrawerContainer;

mode = 'side';
renderDrawer = true;
}

44 changes: 38 additions & 6 deletions src/lib/sidenav/drawer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
OnDestroy,
Inject,
ChangeDetectorRef,
OnChanges,
SimpleChanges,
} from '@angular/core';
import {animate, state, style, transition, trigger, AnimationEvent} from '@angular/animations';
import {Directionality, coerceBooleanProperty} from '../core';
Expand All @@ -31,7 +33,7 @@ import {ESCAPE} from '../core/keyboard/keycodes';
import {first, takeUntil, startWith} from '../core/rxjs/index';
import {DOCUMENT} from '@angular/platform-browser';
import {merge} from 'rxjs/observable/merge';
import {Subscription} from 'rxjs/Subscription';
import {Subject} from 'rxjs/Subject';


/** Throws an exception when two MdDrawer are matching the same position. */
Expand Down Expand Up @@ -90,7 +92,7 @@ export class MdDrawerToggleResult {
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
})
export class MdDrawer implements AfterContentInit, OnDestroy {
export class MdDrawer implements AfterContentInit, OnDestroy, OnChanges {
private _focusTrap: FocusTrap;
private _elementFocusedBeforeDrawerWasOpened: HTMLElement | null = null;

Expand Down Expand Up @@ -156,6 +158,9 @@ export class MdDrawer implements AfterContentInit, OnDestroy {
/** @deprecated */
@Output('align-changed') onAlignChanged = new EventEmitter<void>();

/** Event emitted when the drawer's mode changes. */
_onModeChanged = new Subject<void>();

get isFocusTrapEnabled() {
// The focus trap is only enabled when the drawer is open in any mode other than side.
return this.opened && this.mode !== 'side';
Expand Down Expand Up @@ -206,6 +211,12 @@ export class MdDrawer implements AfterContentInit, OnDestroy {
}
}

ngOnChanges(changes: SimpleChanges) {
if (changes.mode) {
this._onModeChanged.next();
}
}

/**
* Whether the drawer is opened. We overload this because we trigger an event when it
* starts or end.
Expand Down Expand Up @@ -339,8 +350,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 _onDestroy = new Subject<void>();

/** Inline styles to be applied to the container. */
_styles: { marginLeft: string; marginRight: string; transform: string; };
Expand All @@ -351,22 +362,35 @@ 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._onDestroy).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._updateStyles();
}

this._changeDetectorRef.markForCheck();
});
}

ngOnDestroy() {
this._dirChangeSubscription.unsubscribe();
this._onDestroy.next();
this._onDestroy.complete();
}

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

private _watchDrawerMode(drawer: MdDrawer): void {
takeUntil.call(drawer._onModeChanged, merge(this._drawers.changes, this._onDestroy))
.subscribe(() => {
this._updateStyles();
this._changeDetectorRef.markForCheck();
});
}

/** Toggles the 'mat-drawer-opened' class on the main 'md-drawer-container' element. */
private _setContainerClass(isAdd: boolean): void {
if (isAdd) {
Expand Down

0 comments on commit d816484

Please sign in to comment.