Skip to content

Commit 52ade97

Browse files
devversiontinayuangao
authored andcommitted
feat(sidenav): add disableClose option (#2501)
* 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
1 parent 7fc38b9 commit 52ade97

File tree

2 files changed

+63
-11
lines changed

2 files changed

+63
-11
lines changed

src/lib/sidenav/sidenav.spec.ts

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ describe('MdSidenav', () => {
194194
}).not.toThrow();
195195
}));
196196

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

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

267+
it('should not close by pressing escape when disableClose is set', fakeAsync(() => {
268+
let fixture = TestBed.createComponent(BasicTestApp);
269+
let testComponent = fixture.debugElement.componentInstance;
270+
let sidenav = fixture.debugElement.query(By.directive(MdSidenav)).componentInstance;
271+
272+
sidenav.disableClose = true;
273+
sidenav.open();
274+
275+
fixture.detectChanges();
276+
endSidenavTransition(fixture);
277+
tick();
278+
279+
sidenav.handleKeydown({
280+
keyCode: ESCAPE,
281+
stopPropagation: () => {}
282+
});
283+
284+
fixture.detectChanges();
285+
endSidenavTransition(fixture);
286+
tick();
287+
288+
expect(testComponent.closeCount).toBe(0);
289+
}));
290+
291+
it('should not close by clicking on the backdrop when disableClose is set', fakeAsync(() => {
292+
let fixture = TestBed.createComponent(BasicTestApp);
293+
let testComponent = fixture.debugElement.componentInstance;
294+
let sidenav = fixture.debugElement.query(By.directive(MdSidenav)).componentInstance;
295+
296+
sidenav.disableClose = true;
297+
sidenav.open();
298+
299+
fixture.detectChanges();
300+
endSidenavTransition(fixture);
301+
tick();
302+
303+
let backdropEl = fixture.debugElement.query(By.css('.md-sidenav-backdrop')).nativeElement;
304+
backdropEl.click();
305+
fixture.detectChanges();
306+
tick();
307+
308+
fixture.detectChanges();
309+
endSidenavTransition(fixture);
310+
tick();
311+
312+
expect(testComponent.closeCount).toBe(0);
313+
}));
314+
267315
it('should restore focus to the trigger element on close', fakeAsync(() => {
268316
let fixture = TestBed.createComponent(BasicTestApp);
269317
let sidenav: MdSidenav = fixture.debugElement
@@ -414,7 +462,7 @@ class SidenavContainerTwoSidenavTestApp { }
414462
/** Test component that contains an MdSidenavContainer and one MdSidenav. */
415463
@Component({
416464
template: `
417-
<md-sidenav-container (backdrop-clicked)="backdropClicked()">
465+
<md-sidenav-container (backdropClick)="backdropClicked()">
418466
<md-sidenav #sidenav align="start"
419467
(open-start)="openStart()"
420468
(open)="open()"

src/lib/sidenav/sidenav.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ export class MdSidenav implements AfterContentInit {
102102
/** Mode of the sidenav; whether 'over' or 'side'. */
103103
@Input() mode: 'over' | 'push' | 'side' = 'over';
104104

105+
/** Whether the sidenav can be closed with the escape key or not. */
106+
@Input()
107+
get disableClose(): boolean { return this._disableClose; }
108+
set disableClose(value: boolean) { this._disableClose = coerceBooleanProperty(value); }
109+
private _disableClose: boolean = false;
110+
105111
/** Whether the sidenav is opened. */
106112
_opened: boolean = false;
107113

@@ -232,7 +238,7 @@ export class MdSidenav implements AfterContentInit {
232238
* @docs-private
233239
*/
234240
handleKeydown(event: KeyboardEvent) {
235-
if (event.keyCode === ESCAPE) {
241+
if (event.keyCode === ESCAPE && !this.disableClose) {
236242
this.close();
237243
event.stopPropagation();
238244
}
@@ -327,7 +333,7 @@ export class MdSidenavContainer implements AfterContentInit {
327333
get end() { return this._end; }
328334

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

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

436442
_onBackdropClicked() {
437-
this.onBackdropClicked.emit();
443+
this.backdropClick.emit();
438444
this._closeModalSidenav();
439445
}
440446

441447
_closeModalSidenav() {
442-
if (this._start != null && this._start.mode != 'side') {
443-
this._start.close();
444-
}
445-
if (this._end != null && this._end.mode != 'side') {
446-
this._end.close();
447-
}
448+
// Close all open sidenav's where closing is not disabled and the mode is not `side`.
449+
[this._start, this._end]
450+
.filter(sidenav => sidenav && !sidenav.disableClose && sidenav.mode !== 'side')
451+
.forEach(sidenav => sidenav.close());
448452
}
449453

450454
_isShowingBackdrop(): boolean {

0 commit comments

Comments
 (0)