Skip to content

Commit

Permalink
feat(sidenav): add disableClose option (#2501)
Browse files Browse the repository at this point in the history
* feat(sidenav): add disableClose option

* Adds an attribute to the `md-sidenav` component, which allows developers to disable the closing behavior (e.g escape closing)
  Backdrop stays separate because you can disable it by using the `mode` attribute.

Closes #2462

* Address comments
  • Loading branch information
devversion authored and tinayuangao committed Jan 13, 2017
1 parent 7fc38b9 commit 52ade97
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 11 deletions.
52 changes: 50 additions & 2 deletions src/lib/sidenav/sidenav.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ describe('MdSidenav', () => {
}).not.toThrow();
}));

it('should emit the backdrop-clicked event when the backdrop is clicked', fakeAsync(() => {
it('should emit the backdropClick event when the backdrop is clicked', fakeAsync(() => {
let fixture = TestBed.createComponent(BasicTestApp);

let testComponent: BasicTestApp = fixture.debugElement.componentInstance;
Expand Down Expand Up @@ -264,6 +264,54 @@ describe('MdSidenav', () => {
expect(testComponent.closeCount).toBe(1);
}));

it('should not close by pressing escape when disableClose is set', fakeAsync(() => {
let fixture = TestBed.createComponent(BasicTestApp);
let testComponent = fixture.debugElement.componentInstance;
let sidenav = fixture.debugElement.query(By.directive(MdSidenav)).componentInstance;

sidenav.disableClose = true;
sidenav.open();

fixture.detectChanges();
endSidenavTransition(fixture);
tick();

sidenav.handleKeydown({
keyCode: ESCAPE,
stopPropagation: () => {}
});

fixture.detectChanges();
endSidenavTransition(fixture);
tick();

expect(testComponent.closeCount).toBe(0);
}));

it('should not close by clicking on the backdrop when disableClose is set', fakeAsync(() => {
let fixture = TestBed.createComponent(BasicTestApp);
let testComponent = fixture.debugElement.componentInstance;
let sidenav = fixture.debugElement.query(By.directive(MdSidenav)).componentInstance;

sidenav.disableClose = true;
sidenav.open();

fixture.detectChanges();
endSidenavTransition(fixture);
tick();

let backdropEl = fixture.debugElement.query(By.css('.md-sidenav-backdrop')).nativeElement;
backdropEl.click();
fixture.detectChanges();
tick();

fixture.detectChanges();
endSidenavTransition(fixture);
tick();

expect(testComponent.closeCount).toBe(0);
}));

it('should restore focus to the trigger element on close', fakeAsync(() => {
let fixture = TestBed.createComponent(BasicTestApp);
let sidenav: MdSidenav = fixture.debugElement
Expand Down Expand Up @@ -414,7 +462,7 @@ class SidenavContainerTwoSidenavTestApp { }
/** Test component that contains an MdSidenavContainer and one MdSidenav. */
@Component({
template: `
<md-sidenav-container (backdrop-clicked)="backdropClicked()">
<md-sidenav-container (backdropClick)="backdropClicked()">
<md-sidenav #sidenav align="start"
(open-start)="openStart()"
(open)="open()"
Expand Down
22 changes: 13 additions & 9 deletions src/lib/sidenav/sidenav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ export class MdSidenav implements AfterContentInit {
/** Mode of the sidenav; whether 'over' or 'side'. */
@Input() mode: 'over' | 'push' | 'side' = 'over';

/** Whether the sidenav can be closed with the escape key or not. */
@Input()
get disableClose(): boolean { return this._disableClose; }
set disableClose(value: boolean) { this._disableClose = coerceBooleanProperty(value); }
private _disableClose: boolean = false;

/** Whether the sidenav is opened. */
_opened: boolean = false;

Expand Down Expand Up @@ -232,7 +238,7 @@ export class MdSidenav implements AfterContentInit {
* @docs-private
*/
handleKeydown(event: KeyboardEvent) {
if (event.keyCode === ESCAPE) {
if (event.keyCode === ESCAPE && !this.disableClose) {
this.close();
event.stopPropagation();
}
Expand Down Expand Up @@ -327,7 +333,7 @@ export class MdSidenavContainer implements AfterContentInit {
get end() { return this._end; }

/** Event emitted when the sidenav backdrop is clicked. */
@Output('backdrop-clicked') onBackdropClicked = new EventEmitter<void>();
@Output() backdropClick = new EventEmitter<void>();

/** The sidenav at the start/end alignment, independent of direction. */
private _start: MdSidenav;
Expand Down Expand Up @@ -434,17 +440,15 @@ export class MdSidenavContainer implements AfterContentInit {
}

_onBackdropClicked() {
this.onBackdropClicked.emit();
this.backdropClick.emit();
this._closeModalSidenav();
}

_closeModalSidenav() {
if (this._start != null && this._start.mode != 'side') {
this._start.close();
}
if (this._end != null && this._end.mode != 'side') {
this._end.close();
}
// Close all open sidenav's where closing is not disabled and the mode is not `side`.
[this._start, this._end]
.filter(sidenav => sidenav && !sidenav.disableClose && sidenav.mode !== 'side')
.forEach(sidenav => sidenav.close());
}

_isShowingBackdrop(): boolean {
Expand Down

0 comments on commit 52ade97

Please sign in to comment.