From 19c7444585bd71de9550c47d2cb393a378f0a44b Mon Sep 17 00:00:00 2001 From: Michael Prentice Date: Sat, 10 Oct 2020 22:28:09 -0400 Subject: [PATCH] fix(datepicker): time is modified before even selecting a date - `updateErrorState()` was mutating the model incorrectly and clearing the time to midnight when the datepicker is first interacted with, without selecting a date Fixes #12028. Closes #12026. --- src/components/datepicker/js/calendar.js | 2 +- .../datepicker/js/datepickerDirective.js | 19 ++++++++++++++----- .../datepicker/js/datepickerDirective.spec.js | 7 ++++++- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/components/datepicker/js/calendar.js b/src/components/datepicker/js/calendar.js index c6f1f3414bb..b30ae1d5d89 100644 --- a/src/components/datepicker/js/calendar.js +++ b/src/components/datepicker/js/calendar.js @@ -174,7 +174,7 @@ /** * The date that is currently focused or showing in the calendar. This will initially be set * to the ng-model value if set, otherwise to today. It will be updated as the user navigates - * to other months. The cell corresponding to the displayDate does not necesarily always have + * to other months. The cell corresponding to the displayDate does not necessarily always have * focus in the document (such as for cases when the user is scrolling the calendar). * @type {Date} */ diff --git a/src/components/datepicker/js/datepickerDirective.js b/src/components/datepicker/js/datepickerDirective.js index 7eca3b1e456..de48332a1ab 100644 --- a/src/components/datepicker/js/datepickerDirective.js +++ b/src/components/datepicker/js/datepickerDirective.js @@ -339,7 +339,10 @@ */ this.$scope = $scope; - /** @type {Date} */ + /** + * This holds the model that will be used by the calendar. + * @type {Date|null|undefined} + */ this.date = null; /** @type {boolean} */ @@ -631,7 +634,12 @@ * @param {Date=} opt_date Date to check. If not given, defaults to the datepicker's model value. */ DatePickerCtrl.prototype.updateErrorState = function(opt_date) { - var date = opt_date || this.date; + var date; + if (opt_date) { + date = new Date(opt_date.valueOf()); + } else { + date = angular.copy(this.ngModelCtrl.$modelValue); + } // Clear any existing errors to get rid of anything that's no longer relevant. this.clearErrorState(); @@ -840,7 +848,7 @@ /** * Open the floating calendar pane. - * @param {Event} event + * @param {MouseEvent|KeyboardEvent|{target: HTMLInputElement}} event */ DatePickerCtrl.prototype.openCalendarPane = function(event) { if (!this.isCalendarOpen && !this.isDisabled && !this.inputFocusedOnWindowBlur) { @@ -901,7 +909,7 @@ } } - function reset(){ + function reset() { self.isCalendarOpen = self.isOpen = false; } }; @@ -916,7 +924,7 @@ // Use a timeout in order to allow the calendar to be rendered, as it is gated behind an ng-if. var self = this; this.$mdUtil.nextTick(function() { - self.getCalendarCtrl().focusDate(); + self.getCalendarCtrl().focusDate(self.date); }, false); }; @@ -1007,6 +1015,7 @@ var self = this; var timezone = this.$mdUtil.getModelOption(this.ngModelCtrl, 'timezone'); + // Update the model used by the calendar. if (this.dateUtil.isValidDate(value) && timezone != null && value.getTimezoneOffset() >= 0) { this.date = this.dateUtil.removeLocalTzAndReparseDate(value); } else { diff --git a/src/components/datepicker/js/datepickerDirective.spec.js b/src/components/datepicker/js/datepickerDirective.spec.js index 57881f18807..f0ace5e48fc 100644 --- a/src/components/datepicker/js/datepickerDirective.spec.js +++ b/src/components/datepicker/js/datepickerDirective.spec.js @@ -153,7 +153,12 @@ describe('md-datepicker', function() { createDatepickerInstance( ''); - expect(controller.locale.formatDate).toHaveBeenCalledWith(pageScope.myDate, 'UTC'); + // If running in a GMT+X timezone, formatDate will not be called with a timezone argument. + if (pageScope.myDate.getTimezoneOffset() < 0) { + expect(controller.locale.formatDate).toHaveBeenCalledWith(pageScope.myDate); + } else { + expect(controller.locale.formatDate).toHaveBeenCalledWith(pageScope.myDate, 'UTC'); + } }); it('should allow for the locale to be overwritten on a specific element', function() {