Skip to content

Commit e73875b

Browse files
authored
fix(datepicker): end input reset on load when bound through ngModel (#19176)
This is something I found while I was writing the live examples. When both the start and end inputs have an initial value bound through `ngModel`, the start resets the end, because the end's value wasn't yet defined at the time the start was assigning its value. These changes fix the issue by treating the entire input as a single unit when it comes to change events.
1 parent 8fd3b2f commit e73875b

File tree

2 files changed

+45
-3
lines changed

2 files changed

+45
-3
lines changed

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,12 @@ export class MatStartDate<D> extends _MatDateRangeInputBase<D> implements CanUpd
224224

225225
protected _assignValueToModel(value: D | null) {
226226
if (this._model) {
227-
this._model.updateSelection(new DateRange(value, this._model.selection.end), this);
227+
const range = new DateRange(value, this._model.selection.end);
228+
229+
// Note that we pass the range input as the source of the event, rather than the current
230+
// field, because we treat the whole input as a single unit and we don't want the two
231+
// inner inputs to respond to each other's changes.
232+
this._model.updateSelection(range, this._rangeInput);
228233
}
229234
}
230235

@@ -304,7 +309,12 @@ export class MatEndDate<D> extends _MatDateRangeInputBase<D> implements CanUpdat
304309

305310
protected _assignValueToModel(value: D | null) {
306311
if (this._model) {
307-
this._model.updateSelection(new DateRange(this._model.selection.start, value), this);
312+
const range = new DateRange(this._model.selection.start, value);
313+
314+
// Note that we pass the range input as the source of the event, rather than the current
315+
// field, because we treat the whole input as a single unit and we don't want the two
316+
// inner inputs to respond to each other's changes.
317+
this._model.updateSelection(range, this._rangeInput);
308318
}
309319
}
310320

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

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Type, Component, ViewChild, ElementRef} from '@angular/core';
2-
import {ComponentFixture, TestBed, inject} from '@angular/core/testing';
2+
import {ComponentFixture, TestBed, inject, fakeAsync, tick} from '@angular/core/testing';
33
import {FormsModule, ReactiveFormsModule, FormGroup, FormControl} from '@angular/forms';
44
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
55
import {OverlayContainer} from '@angular/cdk/overlay';
@@ -452,6 +452,20 @@ describe('MatDatepicker', () => {
452452
expect(rangeTexts).toEqual(['2', '3', '4', '5']);
453453
});
454454

455+
it('should preserve the preselected values when assigning through ngModel', fakeAsync(() => {
456+
const start = new Date(2020, 1, 2);
457+
const end = new Date(2020, 1, 2);
458+
const fixture = createComponent(RangePickerNgModel);
459+
fixture.componentInstance.start = start;
460+
fixture.componentInstance.end = end;
461+
fixture.detectChanges();
462+
tick();
463+
fixture.detectChanges();
464+
465+
expect(fixture.componentInstance.start).toBe(start);
466+
expect(fixture.componentInstance.end).toBe(end);
467+
}));
468+
455469
});
456470

457471
@Component({
@@ -524,3 +538,21 @@ class RangePickerNoStart {}
524538
})
525539
class RangePickerNoEnd {}
526540

541+
542+
@Component({
543+
template: `
544+
<mat-form-field>
545+
<mat-date-range-input [rangePicker]="rangePicker">
546+
<input matStartDate [(ngModel)]="start"/>
547+
<input matEndDate [(ngModel)]="end"/>
548+
</mat-date-range-input>
549+
550+
<mat-date-range-picker #rangePicker></mat-date-range-picker>
551+
</mat-form-field>
552+
`
553+
})
554+
class RangePickerNgModel {
555+
start: Date | null = null;
556+
end: Date | null = null;
557+
}
558+

0 commit comments

Comments
 (0)