From ad9a0326c9f078bd9ae6a50ac909cd8c75655f9d Mon Sep 17 00:00:00 2001 From: crisbeto Date: Wed, 18 Jul 2018 07:11:47 +0200 Subject: [PATCH] fix(datepicker): multiple dialog open if the user holds down enter key Fixes the case where the user might be holding down the enter key for a datepicker in touch mode, which could cause it to open multiple dialogs at the same time. --- src/lib/datepicker/datepicker.spec.ts | 26 ++++++++++++++++++++++++-- src/lib/datepicker/datepicker.ts | 8 ++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/lib/datepicker/datepicker.spec.ts b/src/lib/datepicker/datepicker.spec.ts index d72646bb1c40..40de62935cc9 100644 --- a/src/lib/datepicker/datepicker.spec.ts +++ b/src/lib/datepicker/datepicker.spec.ts @@ -8,7 +8,7 @@ import { dispatchMouseEvent, } from '@angular/cdk/testing'; import {Component, FactoryProvider, Type, ValueProvider, ViewChild} from '@angular/core'; -import {ComponentFixture, fakeAsync, flush, inject, TestBed} from '@angular/core/testing'; +import {ComponentFixture, fakeAsync, flush, inject, TestBed, tick} from '@angular/core/testing'; import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; import { DEC, @@ -102,7 +102,7 @@ describe('MatDatepicker', () => { expect(document.querySelector('.cdk-overlay-pane.mat-datepicker-popup')).not.toBeNull(); }); - it('open touch should open dialog', () => { + it('touch should open dialog', () => { testComponent.touch = true; fixture.detectChanges(); @@ -115,6 +115,28 @@ describe('MatDatepicker', () => { .not.toBeNull(); }); + it('should not be able to open more than one dialog', fakeAsync(() => { + testComponent.touch = true; + fixture.detectChanges(); + + expect(document.querySelectorAll('.mat-datepicker-dialog').length).toBe(0); + + testComponent.datepicker.open(); + fixture.detectChanges(); + tick(500); + fixture.detectChanges(); + + dispatchKeyboardEvent(document.querySelector('.mat-calendar-body')!, 'keydown', ENTER); + fixture.detectChanges(); + tick(100); + + testComponent.datepicker.open(); + tick(500); + fixture.detectChanges(); + + expect(document.querySelectorAll('.mat-datepicker-dialog').length).toBe(1); + })); + it('should open datepicker if opened input is set to true', fakeAsync(() => { testComponent.opened = true; fixture.detectChanges(); diff --git a/src/lib/datepicker/datepicker.ts b/src/lib/datepicker/datepicker.ts index 3ea51260165e..9b73f33309f9 100644 --- a/src/lib/datepicker/datepicker.ts +++ b/src/lib/datepicker/datepicker.ts @@ -380,6 +380,14 @@ export class MatDatepicker implements OnDestroy, CanColor { /** Open the calendar as a dialog. */ private _openAsDialog(): void { + // Usually this would be handled by `open` which ensures that we can only have one overlay + // open at a time, however since we reset the variables in async handlers some overlays + // may slip through if the user opens and closes multiple times in quick succession (e.g. + // by holding down the enter key). + if (this._dialogRef) { + this._dialogRef.close(); + } + this._dialogRef = this._dialog.open>(MatDatepickerContent, { direction: this._dir ? this._dir.value : 'ltr', viewContainerRef: this._viewContainerRef,