diff --git a/src/material/datepicker/datepicker-input.ts b/src/material/datepicker/datepicker-input.ts index bb74cceab489..29bd5b71a1c8 100644 --- a/src/material/datepicker/datepicker-input.ts +++ b/src/material/datepicker/datepicker-input.ts @@ -320,6 +320,7 @@ export class MatDatepickerInput implements ControlValueAccessor, OnDestroy, V } _onInput(value: string) { + const lastValueWasValid = this._lastValueValid; let date = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput); this._lastValueValid = !date || this._dateAdapter.isValid(date); date = this._getValidDateOrNull(date); @@ -329,7 +330,7 @@ export class MatDatepickerInput implements ControlValueAccessor, OnDestroy, V this._cvaOnChange(date); this._valueChange.emit(date); this.dateInput.emit(new MatDatepickerInputEvent(this, this._elementRef.nativeElement)); - } else { + } else if (lastValueWasValid !== this._lastValueValid) { this._validatorOnChange(); } } diff --git a/src/material/datepicker/datepicker.spec.ts b/src/material/datepicker/datepicker.spec.ts index 23784b20251b..c07b90c8a7ed 100644 --- a/src/material/datepicker/datepicker.spec.ts +++ b/src/material/datepicker/datepicker.spec.ts @@ -876,6 +876,44 @@ describe('MatDatepicker', () => { expect(testComponent.datepickerToggle.disabled).toBe(true); }); + + it('should not dispatch FormControl change event for invalid values on input when set ' + + 'to update on blur', fakeAsync(() => { + const formControl = new FormControl({value: null}, {updateOn: 'blur'}); + const spy = jasmine.createSpy('change spy'); + const subscription = formControl.valueChanges.subscribe(spy); + const inputEl = fixture.debugElement.query(By.css('input'))!.nativeElement; + const setValue = (value: string) => { + inputEl.value = value; + dispatchFakeEvent(inputEl, 'input'); + fixture.detectChanges(); + flush(); + fixture.detectChanges(); + }; + + fixture.componentInstance.formControl = formControl; + fixture.detectChanges(); + + expect(spy).not.toHaveBeenCalled(); + + setValue('10/10/2010'); + expect(spy).not.toHaveBeenCalled(); + + setValue('10/10/'); + expect(spy).not.toHaveBeenCalled(); + + setValue('10/10'); + expect(spy).not.toHaveBeenCalled(); + + dispatchFakeEvent(inputEl, 'blur'); + fixture.detectChanges(); + flush(); + fixture.detectChanges(); + + expect(spy).toHaveBeenCalledTimes(1); + subscription.unsubscribe(); + })); + }); describe('datepicker with mat-datepicker-toggle', () => {