From 004e0fef2fe5172b6e6ed2c4d368d21dab051355 Mon Sep 17 00:00:00 2001 From: Austin Date: Mon, 9 Oct 2017 17:50:30 -0500 Subject: [PATCH] chore(api): new output api #6677 (#7450) * chore(api): new output api #6677 * chore(nit): add 2way test and nit spacing --- src/lib/sidenav/drawer.spec.ts | 33 ++++++++++++++++-- src/lib/sidenav/drawer.ts | 62 +++++++++++++++++++++++++--------- 2 files changed, 76 insertions(+), 19 deletions(-) diff --git a/src/lib/sidenav/drawer.spec.ts b/src/lib/sidenav/drawer.spec.ts index ccd132030d2c..b3f941de525a 100644 --- a/src/lib/sidenav/drawer.spec.ts +++ b/src/lib/sidenav/drawer.spec.ts @@ -20,6 +20,7 @@ describe('MatDrawer', () => { DrawerSetToOpenedTrue, DrawerDynamicPosition, DrawerWitFocusableElements, + DrawerOpenBinding, ], }); @@ -287,6 +288,20 @@ describe('MatDrawer', () => { expect(() => fixture.detectChanges()).not.toThrow(); }); + + it('should bind 2-way bind on opened property', fakeAsync(() => { + const fixture = TestBed.createComponent(DrawerOpenBinding); + fixture.detectChanges(); + + let drawer: MatDrawer = fixture.debugElement + .query(By.directive(MatDrawer)).componentInstance; + + drawer.open(); + fixture.detectChanges(); + tick(); + + expect(fixture.componentInstance.isOpen).toBe(true); + })); }); describe('focus trapping behavior', () => { @@ -474,8 +489,8 @@ class DrawerContainerTwoDrawerTestApp { template: ` + (opened)="open()" + (closed)="close()"> @@ -517,7 +532,7 @@ class DrawerSetToOpenedFalse { } @Component({ template: ` - + Closed Drawer. `, @@ -526,6 +541,18 @@ class DrawerSetToOpenedTrue { openCallback = jasmine.createSpy('open callback'); } +@Component({ + template: ` + + + Closed Drawer. + + `, +}) +class DrawerOpenBinding { + isOpen = false; +} + @Component({ template: ` diff --git a/src/lib/sidenav/drawer.ts b/src/lib/sidenav/drawer.ts index 4a82ff1b0d03..9fd9a2b449a7 100644 --- a/src/lib/sidenav/drawer.ts +++ b/src/lib/sidenav/drawer.ts @@ -34,7 +34,8 @@ import { import {DOCUMENT} from '@angular/platform-browser'; import {merge} from 'rxjs/observable/merge'; import {Subject} from 'rxjs/Subject'; -import {RxChain, filter, first, startWith, takeUntil} from '@angular/cdk/rxjs'; +import {Observable} from 'rxjs/Observable'; +import {RxChain, filter, map, first, startWith, takeUntil} from '@angular/cdk/rxjs'; /** Throws an exception when two MatDrawer are matching the same position. */ @@ -177,11 +178,38 @@ export class MatDrawer implements AfterContentInit, OnDestroy { /** Current state of the sidenav animation. */ _animationState: 'open-instant' | 'open' | 'void' = 'void'; - /** Event emitted when the drawer is fully opened. */ - @Output('open') onOpen = new EventEmitter(); + /** Event emitted when the drawer open state is changed. */ + @Output() openedChange: EventEmitter = new EventEmitter(); - /** Event emitted when the drawer is fully closed. */ - @Output('close') onClose = new EventEmitter(); + /** Event emitted when the drawer has been opened. */ + @Output('opened') + get _openedStream(): Observable { + return RxChain.from(this.openedChange) + .call(filter, o => o) + .call(map, () => {}) + .result(); + } + + /** Event emitted when the drawer has been closed. */ + @Output('closed') + get _closedStream(): Observable { + return RxChain.from(this.openedChange) + .call(filter, o => !o) + .call(map, () => {}) + .result(); + } + + /** + * Event emitted when the drawer is fully opened. + * @deprecated Use `openedChange` instead. + */ + @Output('open') onOpen = this._openedStream; + + /** + * Event emitted when the drawer is fully closed. + * @deprecated Use `openedChange` instead. + */ + @Output('close') onClose = this._closedStream; /** Event emitted when the drawer's position changes. */ @Output('positionChanged') onPositionChanged = new EventEmitter(); @@ -203,17 +231,19 @@ export class MatDrawer implements AfterContentInit, OnDestroy { constructor(private _elementRef: ElementRef, private _focusTrapFactory: FocusTrapFactory, @Optional() @Inject(DOCUMENT) private _doc: any) { - this.onOpen.subscribe(() => { - if (this._doc) { - this._elementFocusedBeforeDrawerWasOpened = this._doc.activeElement as HTMLElement; - } + this.openedChange.subscribe((opened: boolean) => { + if (opened) { + if (this._doc) { + this._elementFocusedBeforeDrawerWasOpened = this._doc.activeElement as HTMLElement; + } - if (this._isFocusTrapEnabled && this._focusTrap) { - this._focusTrap.focusInitialElementWhenReady(); + if (this._isFocusTrapEnabled && this._focusTrap) { + this._focusTrap.focusInitialElementWhenReady(); + } + } else { + this._restoreFocus(); } }); - - this.onClose.subscribe(() => this._restoreFocus()); } /** @@ -309,9 +339,9 @@ export class MatDrawer implements AfterContentInit, OnDestroy { const {fromState, toState} = event; if (toState.indexOf('open') === 0 && fromState === 'void') { - this.onOpen.emit(new MatDrawerToggleResult('open', true)); + this.openedChange.emit(true); } else if (toState === 'void' && fromState.indexOf('open') === 0) { - this.onClose.emit(new MatDrawerToggleResult('close', true)); + this.openedChange.emit(false); } } @@ -438,7 +468,7 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy { }); if (drawer.mode !== 'side') { - takeUntil.call(merge(drawer.onOpen, drawer.onClose), this._drawers.changes).subscribe(() => + takeUntil.call(drawer.openedChange, this._drawers.changes).subscribe(() => this._setContainerClass(drawer.opened)); } }