diff --git a/src/demo-app/drawer/drawer-demo.html b/src/demo-app/drawer/drawer-demo.html
index a7f54541bc12..56fa3c7fe6e8 100644
--- a/src/demo-app/drawer/drawer-demo.html
+++ b/src/demo-app/drawer/drawer-demo.html
@@ -1,7 +1,7 @@
Basic Use Case
-
+
Start Side Drawer
diff --git a/src/lib/sidenav/drawer.spec.ts b/src/lib/sidenav/drawer.spec.ts
index b3f941de525a..317cb43cdc0e 100644
--- a/src/lib/sidenav/drawer.spec.ts
+++ b/src/lib/sidenav/drawer.spec.ts
@@ -28,45 +28,94 @@ describe('MatDrawer', () => {
}));
describe('methods', () => {
- it('should be able to open and close', fakeAsync(() => {
- let fixture = TestBed.createComponent(BasicTestApp);
+ it('should be able to open', fakeAsync(() => {
+ const fixture = TestBed.createComponent(BasicTestApp);
fixture.detectChanges();
- let testComponent: BasicTestApp = fixture.debugElement.componentInstance;
- let drawer = fixture.debugElement.query(By.directive(MatDrawer));
- let drawerBackdropElement = fixture.debugElement.query(By.css('.mat-drawer-backdrop'));
+ const testComponent: BasicTestApp = fixture.debugElement.componentInstance;
+ const drawer = fixture.debugElement.query(By.directive(MatDrawer));
+ const drawerBackdropElement = fixture.debugElement.query(By.css('.mat-drawer-backdrop'));
drawerBackdropElement.nativeElement.style.transition = 'none';
fixture.debugElement.query(By.css('.open')).nativeElement.click();
fixture.detectChanges();
expect(testComponent.openCount).toBe(0);
- expect(testComponent.closeCount).toBe(0);
+ expect(testComponent.openStartCount).toBe(0);
tick();
+ expect(testComponent.openStartCount).toBe(1);
fixture.detectChanges();
expect(testComponent.openCount).toBe(1);
- expect(testComponent.closeCount).toBe(0);
+ expect(testComponent.openStartCount).toBe(1);
expect(getComputedStyle(drawer.nativeElement).visibility).toBe('visible');
expect(getComputedStyle(drawerBackdropElement.nativeElement).visibility).toBe('visible');
+ }));
+
+ it('should be able to close', fakeAsync(() => {
+ const fixture = TestBed.createComponent(BasicTestApp);
+
+ fixture.detectChanges();
+
+ const testComponent: BasicTestApp = fixture.debugElement.componentInstance;
+ const drawer = fixture.debugElement.query(By.directive(MatDrawer));
+ const drawerBackdropElement = fixture.debugElement.query(By.css('.mat-drawer-backdrop'));
+
+ drawerBackdropElement.nativeElement.style.transition = 'none';
+ fixture.debugElement.query(By.css('.open')).nativeElement.click();
+ fixture.detectChanges();
+ tick();
+ fixture.detectChanges();
fixture.debugElement.query(By.css('.close')).nativeElement.click();
fixture.detectChanges();
- expect(testComponent.openCount).toBe(1);
expect(testComponent.closeCount).toBe(0);
+ expect(testComponent.closeStartCount).toBe(0);
tick();
+ expect(testComponent.closeStartCount).toBe(1);
fixture.detectChanges();
- expect(testComponent.openCount).toBe(1);
expect(testComponent.closeCount).toBe(1);
+ expect(testComponent.closeStartCount).toBe(1);
expect(getComputedStyle(drawer.nativeElement).visibility).toBe('hidden');
expect(getComputedStyle(drawerBackdropElement.nativeElement).visibility).toBe('hidden');
}));
+ it('should resolve the open method promise with an object', fakeAsync(() => {
+ const fixture = TestBed.createComponent(BasicTestApp);
+ fixture.detectChanges();
+ const drawer = fixture.debugElement.query(By.directive(MatDrawer));
+
+ drawer.componentInstance.open().then(result => {
+ expect(result).toBeTruthy();
+ expect(result.type).toBe('open');
+ expect(result.animationFinished).toBe(true);
+ });
+ fixture.detectChanges();
+ }));
+
+ it('should resolve the close method promise with an object', fakeAsync(() => {
+ const fixture = TestBed.createComponent(BasicTestApp);
+ fixture.detectChanges();
+ const drawer = fixture.debugElement.query(By.directive(MatDrawer));
+
+ drawer.componentInstance.open();
+ fixture.detectChanges();
+ tick();
+ fixture.detectChanges();
+
+ drawer.componentInstance.close().then(result => {
+ expect(result).toBeTruthy();
+ expect(result.type).toBe('close');
+ expect(result.animationFinished).toBe(true);
+ });
+ fixture.detectChanges();
+ }));
+
it('should be able to close while the open animation is running', fakeAsync(() => {
const fixture = TestBed.createComponent(BasicTestApp);
fixture.detectChanges();
@@ -139,13 +188,16 @@ describe('MatDrawer', () => {
tick();
expect(testComponent.openCount).toBe(1, 'Expected one open event.');
+ expect(testComponent.openStartCount).toBe(1, 'Expected one open start event.');
expect(testComponent.closeCount).toBe(0, 'Expected no close events.');
+ expect(testComponent.closeStartCount).toBe(0, 'Expected no close start events.');
dispatchKeyboardEvent(drawer.nativeElement, 'keydown', ESCAPE);
fixture.detectChanges();
tick();
expect(testComponent.closeCount).toBe(1, 'Expected one close event.');
+ expect(testComponent.closeStartCount).toBe(1, 'Expected one close start event.');
}));
it('should fire the open event when open on init', fakeAsync(() => {
@@ -172,6 +224,7 @@ describe('MatDrawer', () => {
tick();
expect(testComponent.closeCount).toBe(0);
+ expect(testComponent.closeStartCount).toBe(0);
}));
it('should not close by clicking on the backdrop when disableClose is set', fakeAsync(() => {
@@ -189,6 +242,7 @@ describe('MatDrawer', () => {
tick();
expect(testComponent.closeCount).toBe(0);
+ expect(testComponent.closeStartCount).toBe(0);
}));
it('should restore focus on close if focus is inside drawer', fakeAsync(() => {
@@ -490,7 +544,9 @@ class DrawerContainerTwoDrawerTestApp {
+ (openedStart)="openStart()"
+ (closed)="close()"
+ (closedStart)="closeStart()">
@@ -498,9 +554,11 @@ class DrawerContainerTwoDrawerTestApp {
`,
})
class BasicTestApp {
- openCount: number = 0;
- closeCount: number = 0;
- backdropClickedCount: number = 0;
+ openCount = 0;
+ openStartCount = 0;
+ closeCount = 0;
+ closeStartCount = 0;
+ backdropClickedCount = 0;
@ViewChild('drawerButton') drawerButton: ElementRef;
@ViewChild('openButton') openButton: ElementRef;
@@ -510,10 +568,18 @@ class BasicTestApp {
this.openCount++;
}
+ openStart() {
+ this.openStartCount++;
+ }
+
close() {
this.closeCount++;
}
+ closeStart() {
+ this.closeStartCount++;
+ }
+
backdropClicked() {
this.backdropClickedCount++;
}
diff --git a/src/lib/sidenav/drawer.ts b/src/lib/sidenav/drawer.ts
index 51193b112e3a..f4c1f6d79e37 100644
--- a/src/lib/sidenav/drawer.ts
+++ b/src/lib/sidenav/drawer.ts
@@ -190,6 +190,15 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
.result();
}
+ /** Event emitted when the drawer has started opening. */
+ @Output()
+ get openedStart(): Observable {
+ return RxChain.from(this._animationStarted)
+ .call(filter, e => e.fromState !== e.toState && e.toState.indexOf('open') === 0)
+ .call(map, () => {})
+ .result();
+ }
+
/** Event emitted when the drawer has been closed. */
@Output('closed')
get _closedStream(): Observable {
@@ -199,15 +208,24 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
.result();
}
+ /** Event emitted when the drawer has started closing. */
+ @Output()
+ get closedStart(): Observable {
+ return RxChain.from(this._animationStarted)
+ .call(filter, e => e.fromState !== e.toState && e.toState === 'void')
+ .call(map, () => {})
+ .result();
+ }
+
/**
* Event emitted when the drawer is fully opened.
- * @deprecated Use `openedChange` instead.
+ * @deprecated Use `opened` instead.
*/
@Output('open') onOpen = this._openedStream;
/**
* Event emitted when the drawer is fully closed.
- * @deprecated Use `openedChange` instead.
+ * @deprecated Use `closed` instead.
*/
@Output('close') onClose = this._closedStream;
@@ -316,8 +334,10 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
// TODO(crisbeto): This promise is here for backwards-compatibility.
// It should be removed next time we do breaking changes in the drawer.
- return new Promise(resolve => {
- first.call(isOpen ? this.onOpen : this.onClose).subscribe(resolve);
+ return new Promise(resolve => {
+ first.call(this.openedChange).subscribe(open => {
+ resolve(new MatDrawerToggleResult(open ? 'open' : 'close', true));
+ });
});
}