Skip to content

Commit a600bf7

Browse files
committed
Use MatDateSelectionModel to model the selected value in MatDatepickerInput
1 parent c40a0fd commit a600bf7

File tree

2 files changed

+41
-25
lines changed

2 files changed

+41
-25
lines changed

src/material/datepicker/datepicker-input.ts

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ import {
2929
ValidatorFn,
3030
Validators,
3131
} from '@angular/forms';
32-
import {DateAdapter, MAT_DATE_FORMATS, MatDateFormats, ThemePalette} from '@angular/material/core';
32+
import {
33+
DateAdapter,
34+
MAT_DATE_FORMATS,
35+
MatSingleDateSelectionModel,
36+
MatDateFormats,
37+
ThemePalette,
38+
} from '@angular/material/core';
3339
import {MatFormField} from '@angular/material/form-field';
3440
import {MAT_INPUT_VALUE_ACCESSOR} from '@angular/material/input';
3541
import {Subscription} from 'rxjs';
@@ -123,25 +129,33 @@ export class MatDatepickerInput<D> implements ControlValueAccessor, OnDestroy, V
123129

124130
/** The value of the input. */
125131
@Input()
126-
get value(): D | null { return this._value; }
132+
get value(): D | null { return this._value ? this._value.asDate() : null; }
127133
set value(value: D | null) {
128-
value = this._dateAdapter.deserialize(value);
129-
this._lastValueValid = !value || this._dateAdapter.isValid(value);
130-
value = this._getValidDateOrNull(value);
131-
const oldDate = this.value;
132-
this._value = value;
133-
this._formatValue(value);
134-
134+
value = this._dateAdapter.deserialize(value);
135+
const oldDate = this._value.asDate();
136+
let isDifferent = false;
135137
if (!this._dateAdapter.sameDate(oldDate, value)) {
136-
this._valueChange.emit(value);
138+
isDifferent = true;
139+
}
140+
this._value.add(value);
141+
142+
this._lastValueValid = !this._value || this._value.isValid();
143+
144+
if (this._value) {
145+
this._formatValue(this._value.asDate());
146+
}
147+
148+
if (isDifferent) {
149+
this._valueChange.emit(this.value);
137150
}
138151
}
139-
private _value: D | null;
152+
private _value: MatSingleDateSelectionModel<D>;
140153

141154
/** The minimum valid date. */
142155
@Input()
143156
get min(): D | null { return this._min; }
144157
set min(value: D | null) {
158+
value = this._dateAdapter.deserialize(value);
145159
this._min = this._getValidDateOrNull(this._dateAdapter.deserialize(value));
146160
this._validatorOnChange();
147161
}
@@ -226,9 +240,9 @@ export class MatDatepickerInput<D> implements ControlValueAccessor, OnDestroy, V
226240

227241
/** The form control validator for the date filter. */
228242
private _filterValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
229-
const controlValue = this._getValidDateOrNull(this._dateAdapter.deserialize(control.value));
230-
return !this._dateFilter || !controlValue || this._dateFilter(controlValue) ?
231-
null : {'matDatepickerFilter': true};
243+
const controlValueSelection = new MatSingleDateSelectionModel(this._dateAdapter, control.value);
244+
return !this._dateFilter || !controlValueSelection.isValid() ||
245+
this._dateFilter(controlValueSelection.asDate()) ? null : {'matDatepickerFilter': true};
232246
}
233247

234248
/** The combined form control validator for this input. */
@@ -255,6 +269,8 @@ export class MatDatepickerInput<D> implements ControlValueAccessor, OnDestroy, V
255269
this._localeSubscription = _dateAdapter.localeChanges.subscribe(() => {
256270
this.value = this.value;
257271
});
272+
273+
this._value = new MatSingleDateSelectionModel(this._dateAdapter, null);
258274
}
259275

260276
ngOnDestroy() {
@@ -320,14 +336,14 @@ export class MatDatepickerInput<D> implements ControlValueAccessor, OnDestroy, V
320336
}
321337

322338
_onInput(value: string) {
323-
let date = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput);
324-
this._lastValueValid = !date || this._dateAdapter.isValid(date);
325-
date = this._getValidDateOrNull(date);
326-
327-
if (!this._dateAdapter.sameDate(date, this._value)) {
328-
this._value = date;
329-
this._cvaOnChange(date);
330-
this._valueChange.emit(date);
339+
const dateSelection = new MatSingleDateSelectionModel(this._dateAdapter,
340+
this._dateAdapter.parse(value, this._dateFormats.parse.dateInput));
341+
this._lastValueValid = dateSelection.isValid();
342+
343+
if (!dateSelection.isSame(this._value)) {
344+
this._value = dateSelection;
345+
this._cvaOnChange(dateSelection.asDate());
346+
this._valueChange.emit(dateSelection.asDate());
331347
this.dateInput.emit(new MatDatepickerInputEvent(this, this._elementRef.nativeElement));
332348
} else {
333349
this._validatorOnChange();

src/material/datepicker/datepicker.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,9 +1191,9 @@ describe('MatDatepicker', () => {
11911191
.not.toContain('ng-invalid');
11921192
}));
11931193

1194-
it('should update validity when switching between null and invalid', fakeAsync(() => {
1194+
it('should update validity when switching between valid and invalid', fakeAsync(() => {
11951195
const inputEl = fixture.debugElement.query(By.css('input'))!.nativeElement;
1196-
inputEl.value = '';
1196+
inputEl.value = new Date(2010, JAN, 2).toDateString();
11971197
dispatchFakeEvent(inputEl, 'input');
11981198

11991199
fixture.detectChanges();
@@ -1211,7 +1211,7 @@ describe('MatDatepicker', () => {
12111211

12121212
expect(testComponent.model.valid).toBe(false);
12131213

1214-
inputEl.value = '';
1214+
inputEl.value = new Date(2010, JAN, 2).toDateString();
12151215
dispatchFakeEvent(inputEl, 'input');
12161216

12171217
fixture.detectChanges();

0 commit comments

Comments
 (0)