Skip to content

Commit 590fdd2

Browse files
crisbetojelbourn
authored andcommitted
fix(datepicker): not marking as dirty when invalid value is typed in (#19730)
Currently we only mark the datepicker's `ControlValueAccessor` as dirty if the value changed as a result of the user typing something in. The problem is that typing in an invalid value is parsed to `null` which is the same as the default value, causing it not to be marked as dirty. One small complication here that I've added a test for is that we shouldn't be dispatching change events when typing in invalid values. Fixes #19726.
1 parent 0a22e0f commit 590fdd2

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

src/material/datepicker/datepicker-input-base.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,16 @@ export abstract class MatDatepickerInputBase<S, D = ExtractDateTypeFromSelection
307307
this._cvaOnChange(date);
308308
this._valueChange.emit(date);
309309
this.dateInput.emit(new MatDatepickerInputEvent(this, this._elementRef.nativeElement));
310-
} else if (lastValueWasValid !== this._lastValueValid) {
311-
this._validatorOnChange();
310+
} else {
311+
// Call the CVA change handler for invalid values
312+
// since this is what marks the control as dirty.
313+
if (value && !this.value) {
314+
this._cvaOnChange(date);
315+
}
316+
317+
if (lastValueWasValid !== this._lastValueValid) {
318+
this._validatorOnChange();
319+
}
312320
}
313321
}
314322

src/material/datepicker/datepicker.spec.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,18 @@ describe('MatDatepicker', () => {
763763
expect(inputEl.classList).toContain('ng-dirty');
764764
}));
765765

766+
it('should mark input dirty after invalid value is typed in', () => {
767+
let inputEl = fixture.debugElement.query(By.css('input'))!.nativeElement;
768+
769+
expect(inputEl.classList).toContain('ng-pristine');
770+
771+
inputEl.value = 'hello there';
772+
dispatchFakeEvent(inputEl, 'input');
773+
fixture.detectChanges();
774+
775+
expect(inputEl.classList).toContain('ng-dirty');
776+
});
777+
766778
it('should not mark dirty after model change', fakeAsync(() => {
767779
let inputEl = fixture.debugElement.query(By.css('input'))!.nativeElement;
768780

@@ -1504,6 +1516,20 @@ describe('MatDatepicker', () => {
15041516
expect(valueDuringChangeEvent).toBe('1/1/2020');
15051517
});
15061518

1519+
it('should not fire dateInput when typing an invalid value', () => {
1520+
expect(testComponent.onDateInput).not.toHaveBeenCalled();
1521+
1522+
inputEl.value = 'a';
1523+
dispatchFakeEvent(inputEl, 'input');
1524+
fixture.detectChanges();
1525+
expect(testComponent.onDateInput).not.toHaveBeenCalled();
1526+
1527+
inputEl.value = 'b';
1528+
dispatchFakeEvent(inputEl, 'input');
1529+
fixture.detectChanges();
1530+
expect(testComponent.onDateInput).not.toHaveBeenCalled();
1531+
});
1532+
15071533
});
15081534

15091535
describe('with ISO 8601 strings as input', () => {

0 commit comments

Comments
 (0)