diff --git a/src/lib/datepicker/datepicker-input.ts b/src/lib/datepicker/datepicker-input.ts index f3fb60661e69..7784c6c9ce93 100644 --- a/src/lib/datepicker/datepicker-input.ts +++ b/src/lib/datepicker/datepicker-input.ts @@ -87,7 +87,7 @@ export class MatDatepickerInputEvent { '[disabled]': 'disabled', '(input)': '_onInput($event.target.value)', '(change)': '_onChange()', - '(blur)': '_onTouched()', + '(blur)': '_onBlur()', '(keydown)': '_onKeydown($event)', }, exportAs: 'matDatepickerInput', @@ -123,10 +123,10 @@ export class MatDatepickerInput implements AfterContentInit, ControlValueAcce value = this._dateAdapter.deserialize(value); this._lastValueValid = !value || this._dateAdapter.isValid(value); value = this._getValidDateOrNull(value); - let oldDate = this.value; + const oldDate = this.value; this._value = value; - this._elementRef.nativeElement.value = - value ? this._dateAdapter.format(value, this._dateFormats.display.dateInput) : ''; + this._formatValue(value); + if (!this._dateAdapter.sameDate(oldDate, value)) { this._valueChange.emit(value); } @@ -343,6 +343,22 @@ export class MatDatepickerInput implements AfterContentInit, ControlValueAcce return this._formField ? this._formField.color : undefined; } + /** Handles blur events on the input. */ + _onBlur() { + // Reformat the input only if we have a valid value. + if (this.value) { + this._formatValue(this.value); + } + + this._onTouched(); + } + + /** Formats a value and sets it on the input element. */ + private _formatValue(value: D | null) { + this._elementRef.nativeElement.value = + value ? this._dateAdapter.format(value, this._dateFormats.display.dateInput) : ''; + } + /** * @param obj The object to check. * @returns The given object if it is both a date instance and valid, otherwise null. diff --git a/src/lib/datepicker/datepicker.spec.ts b/src/lib/datepicker/datepicker.spec.ts index f04ebc22c650..0908965d8f9c 100644 --- a/src/lib/datepicker/datepicker.spec.ts +++ b/src/lib/datepicker/datepicker.spec.ts @@ -663,6 +663,38 @@ describe('MatDatepicker', () => { expect(inputEl.classList).toContain('ng-touched'); }); + it('should reformat the input value on blur', () => { + if (SUPPORTS_INTL) { + // Skip this test if the internationalization API is not supported in the current + // browser. Browsers like Safari 9 do not support the "Intl" API. + return; + } + + const inputEl = fixture.debugElement.query(By.css('input')).nativeElement; + + inputEl.value = '2001-01-01'; + dispatchFakeEvent(inputEl, 'input'); + fixture.detectChanges(); + + dispatchFakeEvent(inputEl, 'blur'); + fixture.detectChanges(); + + expect(inputEl.value).toBe('1/1/2001'); + }); + + it('should not reformat invalid dates on blur', () => { + const inputEl = fixture.debugElement.query(By.css('input')).nativeElement; + + inputEl.value = 'very-valid-date'; + dispatchFakeEvent(inputEl, 'input'); + fixture.detectChanges(); + + dispatchFakeEvent(inputEl, 'blur'); + fixture.detectChanges(); + + expect(inputEl.value).toBe('very-valid-date'); + }); + it('should mark input touched on calendar selection', fakeAsync(() => { let inputEl = fixture.debugElement.query(By.css('input')).nativeElement;