Skip to content

Commit b6e89de

Browse files
committed
fix(datepicker): date range overriding model value if both fields are changed at the same time
The date range picker inputs are set up so that they only respond to events outside of themselves so that we don't trigger duplicate events. In some cases this can be a problem, because the input can end up ignoring its own call to update the CVA value, causing it to be out of sync. These changes add an extra call that ensures that the model and CVA values are always in sync. Fixes #19588.
1 parent df981ee commit b6e89de

File tree

3 files changed

+22
-11
lines changed

3 files changed

+22
-11
lines changed

src/material/datepicker/date-range-input-parts.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,6 @@ abstract class MatDateRangeInputPartBase<D>
165165
protected _parentDisabled() {
166166
return this._rangeInput._groupDisabled;
167167
}
168-
169-
_registerModel(model: MatDateSelectionModel<DateRange<D>, D>) {
170-
// The very first time the range inputs write their values, they don't know about the value
171-
// of the opposite input. When this is combined with the fact that `NgModel` defers writing
172-
// its value with a `Promise.resolve`, we can get into a situation where the first input
173-
// resets the value of the second. We work around it by deferring the registration of
174-
// the model, allowing the input enough time to assign the initial value.
175-
Promise.resolve().then(() => super._registerModel(model));
176-
}
177168
}
178169

179170
const _MatDateRangeInputBase:
@@ -242,6 +233,7 @@ export class MatStartDate<D> extends _MatDateRangeInputBase<D> implements CanUpd
242233
if (this._model) {
243234
const range = new DateRange(value, this._model.selection.end);
244235
this._model.updateSelection(range, this);
236+
this._cvaOnChange(value);
245237
}
246238
}
247239

@@ -323,11 +315,12 @@ export class MatEndDate<D> extends _MatDateRangeInputBase<D> implements CanUpdat
323315
if (this._model) {
324316
const range = new DateRange(this._model.selection.start, value);
325317
this._model.updateSelection(range, this);
318+
this._cvaOnChange(value);
326319
}
327320
}
328321

329322
_onKeydown(event: KeyboardEvent) {
330-
// If the user is pressing backspace on an empty end input, focus focus back to the start.
323+
// If the user is pressing backspace on an empty end input, move focus back to the start.
331324
if (event.keyCode === BACKSPACE && !this._elementRef.nativeElement.value) {
332325
this._rangeInput._startInput.focus();
333326
}

src/material/datepicker/date-range-input.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,24 @@ describe('MatDateRangeInput', () => {
475475
expect(fixture.componentInstance.end).toBe(end);
476476
}));
477477

478+
it('should preserve the values when assigning both together through ngModel', fakeAsync(() => {
479+
const assignAndAssert = (start: Date, end: Date) => {
480+
fixture.componentInstance.start = start;
481+
fixture.componentInstance.end = end;
482+
fixture.detectChanges();
483+
tick();
484+
fixture.detectChanges();
485+
expect(fixture.componentInstance.start).toBe(start);
486+
expect(fixture.componentInstance.end).toBe(end);
487+
};
488+
489+
const fixture = createComponent(RangePickerNgModel);
490+
fixture.detectChanges();
491+
492+
assignAndAssert(new Date(2020, 1, 2), new Date(2020, 1, 5));
493+
assignAndAssert(new Date(2020, 2, 2), new Date(2020, 2, 5));
494+
}));
495+
478496
it('should move focus to the start input when pressing backspace on an empty end input', () => {
479497
const fixture = createComponent(StandardRangePicker);
480498
fixture.detectChanges();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export abstract class MatDatepickerInputBase<S, D = ExtractDateTypeFromSelection
125125
_onTouched = () => {};
126126
_validatorOnChange = () => {};
127127

128-
private _cvaOnChange: (value: any) => void = () => {};
128+
protected _cvaOnChange: (value: any) => void = () => {};
129129
private _valueChangesSubscription = Subscription.EMPTY;
130130
private _localeSubscription = Subscription.EMPTY;
131131

0 commit comments

Comments
 (0)