From 9034f7cfddd3d10fed2eaee600bae5db5d893c05 Mon Sep 17 00:00:00 2001 From: Hubert Date: Thu, 3 Aug 2017 14:40:13 +0200 Subject: [PATCH 1/5] feat: close calendar after choose the same date again --- src/lib/datepicker/calendar.ts | 4 +--- src/lib/datepicker/datepicker.spec.ts | 20 ++++++++++++++++++++ src/lib/datepicker/month-view.ts | 3 --- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/lib/datepicker/calendar.ts b/src/lib/datepicker/calendar.ts index 897d96241a97..5528bcabaea4 100644 --- a/src/lib/datepicker/calendar.ts +++ b/src/lib/datepicker/calendar.ts @@ -154,9 +154,7 @@ export class MdCalendar implements AfterContentInit, OnDestroy { /** Handles date selection in the month view. */ _dateSelected(date: D): void { - if (!this._dateAdapter.sameDate(date, this.selected)) { - this.selectedChange.emit(date); - } + this.selectedChange.emit(date); } /** Handles month selection in the year view. */ diff --git a/src/lib/datepicker/datepicker.spec.ts b/src/lib/datepicker/datepicker.spec.ts index 6f8a891fca51..895ff027e5dc 100644 --- a/src/lib/datepicker/datepicker.spec.ts +++ b/src/lib/datepicker/datepicker.spec.ts @@ -181,6 +181,26 @@ describe('MdDatepicker', () => { }); }); + it('setting twice to the same selected value should update input and close calendar', () => { + for (let changeCount = 1; changeCount < 3; changeCount++) { + const currentDay = changeCount; + testComponent.datepicker.open(); + fixture.detectChanges(); + + expect(document.querySelector('md-datepicker-content')).not.toBeNull(); + expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, currentDay)); + + let cells = document.querySelectorAll('.mat-calendar-body-cell'); + dispatchMouseEvent(cells[1], 'click'); + fixture.detectChanges(); + } + + fixture.whenStable().then(() => { + expect(document.querySelector('md-dialog-container')).toBeNull(); + expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2)); + }); + }); + it('startAt should fallback to input value', () => { expect(testComponent.datepicker.startAt).toEqual(new Date(2020, JAN, 1)); }); diff --git a/src/lib/datepicker/month-view.ts b/src/lib/datepicker/month-view.ts index 5d15ae7c4bcf..7a0c75e5b54a 100644 --- a/src/lib/datepicker/month-view.ts +++ b/src/lib/datepicker/month-view.ts @@ -116,9 +116,6 @@ export class MdMonthView implements AfterContentInit { /** Handles when a new date is selected. */ _dateSelected(date: number) { - if (this._selectedDate == date) { - return; - } this.selectedChange.emit(this._dateAdapter.createDate( this._dateAdapter.getYear(this.activeDate), this._dateAdapter.getMonth(this.activeDate), date)); From 64301f0f497f1885e202711e94e5b2f71aa03665 Mon Sep 17 00:00:00 2001 From: Hubert Date: Wed, 9 Aug 2017 15:48:35 +0200 Subject: [PATCH 2/5] feat: close calendar by userSelection event --- src/lib/datepicker/calendar.html | 4 +++- src/lib/datepicker/calendar.ts | 11 ++++++++++- src/lib/datepicker/datepicker-content.html | 3 ++- src/lib/datepicker/datepicker-input.ts | 14 +++++++------- src/lib/datepicker/datepicker.ts | 1 - src/lib/datepicker/month-view.ts | 15 ++++++++++++--- 6 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/lib/datepicker/calendar.html b/src/lib/datepicker/calendar.html index ab0532718bc1..14a2ae89df1e 100644 --- a/src/lib/datepicker/calendar.html +++ b/src/lib/datepicker/calendar.html @@ -48,7 +48,9 @@ [activeDate]="_activeDate" [selected]="selected" [dateFilter]="_dateFilterForViews" - (selectedChange)="_dateSelected($event)"> + (selectedChange)="_dateSelected($event)" + (userSelection)="_userSelected()" + > implements AfterContentInit, OnDestroy { /** Emits when the currently selected date changes. */ @Output() selectedChange = new EventEmitter(); + /** Emits when any date is selected */ + @Output() userSelection = new EventEmitter(); + /** Date filter for the month and year views. */ _dateFilterForViews = (date: D) => { return !!date && @@ -154,7 +157,13 @@ export class MdCalendar implements AfterContentInit, OnDestroy { /** Handles date selection in the month view. */ _dateSelected(date: D): void { - this.selectedChange.emit(date); + if (!this._dateAdapter.sameDate(date, this.selected)) { + this.selectedChange.emit(date); + } + } + + _userSelected(): void { + this.userSelection.emit(); } /** Handles month selection in the year view. */ diff --git a/src/lib/datepicker/datepicker-content.html b/src/lib/datepicker/datepicker-content.html index 0f3a70ec7dff..ce4c6fc01b76 100644 --- a/src/lib/datepicker/datepicker-content.html +++ b/src/lib/datepicker/datepicker-content.html @@ -6,5 +6,6 @@ [maxDate]="datepicker._maxDate" [dateFilter]="datepicker._dateFilter" [selected]="datepicker._selected" - (selectedChange)="datepicker._selectAndClose($event)"> + (selectedChange)="datepicker._selectAndClose($event)" + (userSelection)="datepicker.close()"> diff --git a/src/lib/datepicker/datepicker-input.ts b/src/lib/datepicker/datepicker-input.ts index 156e481f9746..43e6ee0309df 100644 --- a/src/lib/datepicker/datepicker-input.ts +++ b/src/lib/datepicker/datepicker-input.ts @@ -224,13 +224,13 @@ export class MdDatepickerInput implements AfterContentInit, ControlValueAcces ngAfterContentInit() { if (this._datepicker) { this._datepickerSubscription = - this._datepicker.selectedChanged.subscribe((selected: D) => { - this.value = selected; - this._cvaOnChange(selected); - this._onTouched(); - this.dateInput.emit(new MdDatepickerInputEvent(this, this._elementRef.nativeElement)); - this.dateChange.emit(new MdDatepickerInputEvent(this, this._elementRef.nativeElement)); - }); + this._datepicker.selectedChanged.subscribe((selected: D) => { + this.value = selected; + this._cvaOnChange(selected); + this._onTouched(); + this.dateInput.emit(new MdDatepickerInputEvent(this, this._elementRef.nativeElement)); + this.dateChange.emit(new MdDatepickerInputEvent(this, this._elementRef.nativeElement)); + }); } } diff --git a/src/lib/datepicker/datepicker.ts b/src/lib/datepicker/datepicker.ts index 759db81cb5d9..a6c9d4256d20 100644 --- a/src/lib/datepicker/datepicker.ts +++ b/src/lib/datepicker/datepicker.ts @@ -230,7 +230,6 @@ export class MdDatepicker implements OnDestroy { if (!this._dateAdapter.sameDate(oldValue, this._selected)) { this.selectedChanged.emit(date); } - this.close(); } /** diff --git a/src/lib/datepicker/month-view.ts b/src/lib/datepicker/month-view.ts index 7a0c75e5b54a..2afd9befcff2 100644 --- a/src/lib/datepicker/month-view.ts +++ b/src/lib/datepicker/month-view.ts @@ -67,6 +67,9 @@ export class MdMonthView implements AfterContentInit { /** Emits when a new date is selected. */ @Output() selectedChange = new EventEmitter(); + /** Emits when date is picked */ + @Output() userSelection = new EventEmitter(); + /** The label for this month (e.g. "January 2017"). */ _monthLabel: string; @@ -116,9 +119,15 @@ export class MdMonthView implements AfterContentInit { /** Handles when a new date is selected. */ _dateSelected(date: number) { - this.selectedChange.emit(this._dateAdapter.createDate( - this._dateAdapter.getYear(this.activeDate), this._dateAdapter.getMonth(this.activeDate), - date)); + if (this._selectedDate != date) { + const selectedYear = this._dateAdapter.getYear(this.activeDate); + const selectedMonth = this._dateAdapter.getMonth(this.activeDate); + const selectedDate = this._dateAdapter.createDate(selectedYear, selectedMonth, date); + + this.selectedChange.emit(selectedDate); + } + + this.userSelection.emit(); } /** Initializes this month view. */ From b3cec45cb69afd678086dfe8043cb50e489b322c Mon Sep 17 00:00:00 2001 From: Hubert Date: Thu, 10 Aug 2017 14:06:55 +0200 Subject: [PATCH 3/5] addressing pr comments --- src/lib/datepicker/calendar.html | 3 +-- src/lib/datepicker/calendar.ts | 4 ++-- src/lib/datepicker/datepicker-content.html | 2 +- src/lib/datepicker/datepicker-input.ts | 12 ++++++------ src/lib/datepicker/datepicker.spec.ts | 12 +++++++----- src/lib/datepicker/datepicker.ts | 2 +- src/lib/datepicker/month-view.ts | 4 ++-- 7 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/lib/datepicker/calendar.html b/src/lib/datepicker/calendar.html index 14a2ae89df1e..5bed9b3e0cf0 100644 --- a/src/lib/datepicker/calendar.html +++ b/src/lib/datepicker/calendar.html @@ -49,8 +49,7 @@ [selected]="selected" [dateFilter]="_dateFilterForViews" (selectedChange)="_dateSelected($event)" - (userSelection)="_userSelected()" - > + (userSelection)="_userSelected()"> implements AfterContentInit, OnDestroy { /** Emits when the currently selected date changes. */ @Output() selectedChange = new EventEmitter(); - /** Emits when any date is selected */ - @Output() userSelection = new EventEmitter(); + /** Emits when any date is selected. */ + @Output() userSelection = new EventEmitter(); /** Date filter for the month and year views. */ _dateFilterForViews = (date: D) => { diff --git a/src/lib/datepicker/datepicker-content.html b/src/lib/datepicker/datepicker-content.html index ce4c6fc01b76..90fcc91b6097 100644 --- a/src/lib/datepicker/datepicker-content.html +++ b/src/lib/datepicker/datepicker-content.html @@ -6,6 +6,6 @@ [maxDate]="datepicker._maxDate" [dateFilter]="datepicker._dateFilter" [selected]="datepicker._selected" - (selectedChange)="datepicker._selectAndClose($event)" + (selectedChange)="datepicker._select($event)" (userSelection)="datepicker.close()"> diff --git a/src/lib/datepicker/datepicker-input.ts b/src/lib/datepicker/datepicker-input.ts index 43e6ee0309df..5beb2c7617aa 100644 --- a/src/lib/datepicker/datepicker-input.ts +++ b/src/lib/datepicker/datepicker-input.ts @@ -225,12 +225,12 @@ export class MdDatepickerInput implements AfterContentInit, ControlValueAcces if (this._datepicker) { this._datepickerSubscription = this._datepicker.selectedChanged.subscribe((selected: D) => { - this.value = selected; - this._cvaOnChange(selected); - this._onTouched(); - this.dateInput.emit(new MdDatepickerInputEvent(this, this._elementRef.nativeElement)); - this.dateChange.emit(new MdDatepickerInputEvent(this, this._elementRef.nativeElement)); - }); + this.value = selected; + this._cvaOnChange(selected); + this._onTouched(); + this.dateInput.emit(new MdDatepickerInputEvent(this, this._elementRef.nativeElement)); + this.dateChange.emit(new MdDatepickerInputEvent(this, this._elementRef.nativeElement)); + }); } } diff --git a/src/lib/datepicker/datepicker.spec.ts b/src/lib/datepicker/datepicker.spec.ts index b0628621fe5c..5ea20dd7908b 100644 --- a/src/lib/datepicker/datepicker.spec.ts +++ b/src/lib/datepicker/datepicker.spec.ts @@ -190,7 +190,8 @@ describe('MdDatepicker', () => { }); }); - it('setting twice to the same selected value should update input and close calendar', () => { + it('clicking the currently selected date should close the calendar without firing selectedChanged', () => { + const selectedChangedSpy = spyOn(testComponent.datepicker.selectedChanged, 'emit').and.callThrough(); for (let changeCount = 1; changeCount < 3; changeCount++) { const currentDay = changeCount; testComponent.datepicker.open(); @@ -205,6 +206,7 @@ describe('MdDatepicker', () => { } fixture.whenStable().then(() => { + expect(selectedChangedSpy.calls.count()).toEqual(1); expect(document.querySelector('md-dialog-container')).toBeNull(); expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2)); }); @@ -382,7 +384,7 @@ describe('MdDatepicker', () => { expect(testComponent.datepickerInput.value).toBeNull(); let selected = new Date(2017, JAN, 1); - testComponent.datepicker._selectAndClose(selected); + testComponent.datepicker._select(selected); fixture.detectChanges(); fixture.whenStable().then(() => { @@ -409,7 +411,7 @@ describe('MdDatepicker', () => { expect(inputEl.classList).toContain('ng-pristine'); - testComponent.datepicker._selectAndClose(new Date(2017, JAN, 1)); + testComponent.datepicker._select(new Date(2017, JAN, 1)); fixture.detectChanges(); fixture.whenStable().then(() => { @@ -455,7 +457,7 @@ describe('MdDatepicker', () => { expect(inputEl.classList).toContain('ng-untouched'); - testComponent.datepicker._selectAndClose(new Date(2017, JAN, 1)); + testComponent.datepicker._select(new Date(2017, JAN, 1)); fixture.detectChanges(); fixture.whenStable().then(() => { @@ -499,7 +501,7 @@ describe('MdDatepicker', () => { expect(testComponent.datepickerInput.value).toBeNull(); let selected = new Date(2017, JAN, 1); - testComponent.datepicker._selectAndClose(selected); + testComponent.datepicker._select(selected); fixture.detectChanges(); expect(testComponent.formControl.value).toEqual(selected); diff --git a/src/lib/datepicker/datepicker.ts b/src/lib/datepicker/datepicker.ts index a6c9d4256d20..7dbeec27a5e0 100644 --- a/src/lib/datepicker/datepicker.ts +++ b/src/lib/datepicker/datepicker.ts @@ -224,7 +224,7 @@ export class MdDatepicker implements OnDestroy { } /** Selects the given date and closes the currently open popup or dialog. */ - _selectAndClose(date: D): void { + _select(date: D): void { let oldValue = this._selected; this._selected = date; if (!this._dateAdapter.sameDate(oldValue, this._selected)) { diff --git a/src/lib/datepicker/month-view.ts b/src/lib/datepicker/month-view.ts index 2afd9befcff2..dcae6a54f400 100644 --- a/src/lib/datepicker/month-view.ts +++ b/src/lib/datepicker/month-view.ts @@ -67,8 +67,8 @@ export class MdMonthView implements AfterContentInit { /** Emits when a new date is selected. */ @Output() selectedChange = new EventEmitter(); - /** Emits when date is picked */ - @Output() userSelection = new EventEmitter(); + /** Emits when any date is selected. */ + @Output() userSelection = new EventEmitter(); /** The label for this month (e.g. "January 2017"). */ _monthLabel: string; From 878e10924d0a42846168c4f95529c5e9e70ea9a4 Mon Sep 17 00:00:00 2001 From: Hubert Date: Thu, 10 Aug 2017 15:20:25 +0200 Subject: [PATCH 4/5] fix for tslint errors --- src/lib/datepicker/datepicker.spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib/datepicker/datepicker.spec.ts b/src/lib/datepicker/datepicker.spec.ts index 5ea20dd7908b..e08adafb2340 100644 --- a/src/lib/datepicker/datepicker.spec.ts +++ b/src/lib/datepicker/datepicker.spec.ts @@ -190,8 +190,10 @@ describe('MdDatepicker', () => { }); }); - it('clicking the currently selected date should close the calendar without firing selectedChanged', () => { - const selectedChangedSpy = spyOn(testComponent.datepicker.selectedChanged, 'emit').and.callThrough(); + it('clicking the currently selected date should close the calendar' + + 'without firing selectedChanged', () => { + const selectedChangedSpy = + spyOn(testComponent.datepicker.selectedChanged, 'emit').and.callThrough(); for (let changeCount = 1; changeCount < 3; changeCount++) { const currentDay = changeCount; testComponent.datepicker.open(); From 0ae408da5ee101c633deeba192137f369d256ee2 Mon Sep 17 00:00:00 2001 From: Hubert Date: Fri, 11 Aug 2017 08:18:44 +0200 Subject: [PATCH 5/5] addressing pr comments --- src/lib/datepicker/datepicker-input.ts | 2 +- src/lib/datepicker/datepicker.spec.ts | 2 +- src/lib/datepicker/datepicker.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/datepicker/datepicker-input.ts b/src/lib/datepicker/datepicker-input.ts index 5beb2c7617aa..156e481f9746 100644 --- a/src/lib/datepicker/datepicker-input.ts +++ b/src/lib/datepicker/datepicker-input.ts @@ -224,7 +224,7 @@ export class MdDatepickerInput implements AfterContentInit, ControlValueAcces ngAfterContentInit() { if (this._datepicker) { this._datepickerSubscription = - this._datepicker.selectedChanged.subscribe((selected: D) => { + this._datepicker.selectedChanged.subscribe((selected: D) => { this.value = selected; this._cvaOnChange(selected); this._onTouched(); diff --git a/src/lib/datepicker/datepicker.spec.ts b/src/lib/datepicker/datepicker.spec.ts index e08adafb2340..b551a84076a0 100644 --- a/src/lib/datepicker/datepicker.spec.ts +++ b/src/lib/datepicker/datepicker.spec.ts @@ -190,7 +190,7 @@ describe('MdDatepicker', () => { }); }); - it('clicking the currently selected date should close the calendar' + + it('clicking the currently selected date should close the calendar ' + 'without firing selectedChanged', () => { const selectedChangedSpy = spyOn(testComponent.datepicker.selectedChanged, 'emit').and.callThrough(); diff --git a/src/lib/datepicker/datepicker.ts b/src/lib/datepicker/datepicker.ts index 7dbeec27a5e0..8b3783e647d4 100644 --- a/src/lib/datepicker/datepicker.ts +++ b/src/lib/datepicker/datepicker.ts @@ -223,7 +223,7 @@ export class MdDatepicker implements OnDestroy { } } - /** Selects the given date and closes the currently open popup or dialog. */ + /** Selects the given date */ _select(date: D): void { let oldValue = this._selected; this._selected = date;