Skip to content

Commit 35c0483

Browse files
mcalmusannieyw
authored andcommitted
fix(material/datepicker): Only update selection when value changed (#21846) (#22369)
(cherry picked from commit 979a4fa)
1 parent 62e9c31 commit 35c0483

File tree

4 files changed

+100
-3
lines changed

4 files changed

+100
-3
lines changed

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,16 @@ export class MatStartDate<D> extends _MatDateRangeInputBase<D> implements
261261
return modelValue.start;
262262
}
263263

264+
protected _shouldHandleChangeEvent(change: DateSelectionModelChange<DateRange<D>>): boolean {
265+
if (!super._shouldHandleChangeEvent(change)) {
266+
return false;
267+
} else {
268+
return !change.oldValue?.start ? !!change.selection.start :
269+
!change.selection.start ||
270+
!!this._dateAdapter.compareDate(change.oldValue.start, change.selection.start);
271+
}
272+
}
273+
264274
protected _assignValueToModel(value: D | null) {
265275
if (this._model) {
266276
const range = new DateRange(value, this._model.selection.end);
@@ -365,6 +375,16 @@ export class MatEndDate<D> extends _MatDateRangeInputBase<D> implements
365375
return modelValue.end;
366376
}
367377

378+
protected _shouldHandleChangeEvent(change: DateSelectionModelChange<DateRange<D>>): boolean {
379+
if (!super._shouldHandleChangeEvent(change)) {
380+
return false;
381+
} else {
382+
return !change.oldValue?.end ? !!change.selection.end :
383+
!change.selection.end ||
384+
!!this._dateAdapter.compareDate(change.oldValue.end, change.selection.end);
385+
}
386+
}
387+
368388
protected _assignValueToModel(value: D | null) {
369389
if (this._model) {
370390
const range = new DateRange(this._model.selection.start, value);

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

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,60 @@ describe('MatDateRangeInput', () => {
865865
expect(endInput.errorStateMatcher).toBe(matcher);
866866
});
867867

868+
869+
it('should only update model for input that changed', fakeAsync(() => {
870+
const fixture = createComponent(RangePickerNgModel);
871+
872+
fixture.detectChanges();
873+
tick();
874+
875+
expect(fixture.componentInstance.startDateModelChangeCount).toBe(0);
876+
expect(fixture.componentInstance.endDateModelChangeCount).toBe(0);
877+
878+
fixture.componentInstance.rangePicker.open();
879+
fixture.detectChanges();
880+
tick();
881+
882+
const fromDate = new Date(2020, 0, 1);
883+
const toDate = new Date(2020, 0, 2);
884+
fixture.componentInstance.rangePicker.select(fromDate);
885+
fixture.detectChanges();
886+
tick();
887+
888+
expect(fixture.componentInstance.startDateModelChangeCount).toBe(1, 'Start Date set once');
889+
expect(fixture.componentInstance.endDateModelChangeCount).toBe(0, 'End Date not set');
890+
891+
fixture.componentInstance.rangePicker.select(toDate);
892+
fixture.detectChanges();
893+
tick();
894+
895+
expect(fixture.componentInstance.startDateModelChangeCount).toBe(1,
896+
'Start Date unchanged (set once)');
897+
expect(fixture.componentInstance.endDateModelChangeCount).toBe(1, 'End Date set once');
898+
899+
fixture.componentInstance.rangePicker.open();
900+
fixture.detectChanges();
901+
tick();
902+
903+
const fromDate2 = new Date(2021, 0, 1);
904+
const toDate2 = new Date(2021, 0, 2);
905+
fixture.componentInstance.rangePicker.select(fromDate2);
906+
fixture.detectChanges();
907+
tick();
908+
909+
expect(fixture.componentInstance.startDateModelChangeCount).toBe(2, 'Start Date set twice');
910+
expect(fixture.componentInstance.endDateModelChangeCount).toBe(2,
911+
'End Date set twice (nulled)');
912+
913+
fixture.componentInstance.rangePicker.select(toDate2);
914+
fixture.detectChanges();
915+
tick();
916+
917+
expect(fixture.componentInstance.startDateModelChangeCount).toBe(2,
918+
'Start Date unchanged (set twice)');
919+
expect(fixture.componentInstance.endDateModelChangeCount).toBe(3, 'End date set three times');
920+
}));
921+
868922
});
869923

870924
@Component({
@@ -959,8 +1013,24 @@ class RangePickerNgModel {
9591013
@ViewChild(MatStartDate, {read: ElementRef}) startInput: ElementRef<HTMLInputElement>;
9601014
@ViewChild(MatEndDate, {read: ElementRef}) endInput: ElementRef<HTMLInputElement>;
9611015
@ViewChild(MatDateRangePicker) rangePicker: MatDateRangePicker<Date>;
962-
start: Date | null = null;
963-
end: Date | null = null;
1016+
private _start: Date|null = null;
1017+
get start(): Date|null {
1018+
return this._start;
1019+
}
1020+
set start(aStart: Date|null) {
1021+
this.startDateModelChangeCount++;
1022+
this._start = aStart;
1023+
}
1024+
private _end: Date|null = null;
1025+
get end(): Date|null {
1026+
return this._end;
1027+
}
1028+
set end(anEnd: Date|null) {
1029+
this.endDateModelChangeCount++;
1030+
this._end = anEnd;
1031+
}
1032+
startDateModelChangeCount = 0;
1033+
endDateModelChangeCount = 0;
9641034
}
9651035

9661036

src/material/datepicker/date-selection-model.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ export interface DateSelectionModelChange<S> {
4242

4343
/** Object that triggered the change. */
4444
source: unknown;
45+
46+
/** Previous value */
47+
oldValue?: S;
4548
}
4649

4750
/**
@@ -69,8 +72,9 @@ export abstract class MatDateSelectionModel<S, D = ExtractDateTypeFromSelection<
6972
* @param source Object that triggered the selection change.
7073
*/
7174
updateSelection(value: S, source: unknown) {
75+
const oldValue = (this as {selection: S}).selection;
7276
(this as {selection: S}).selection = value;
73-
this._selectionChanged.next({selection: value, source});
77+
this._selectionChanged.next({selection: value, source, oldValue});
7478
}
7579

7680
ngOnDestroy() {

tools/public_api_guard/material/datepicker.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export declare class DateRange<D> {
1313
}
1414

1515
export interface DateSelectionModelChange<S> {
16+
oldValue?: S;
1617
selection: S;
1718
source: unknown;
1819
}
@@ -406,6 +407,7 @@ export declare class MatEndDate<D> extends _MatDateRangeInputBase<D> implements
406407
protected _assignValueToModel(value: D | null): void;
407408
protected _getValueFromModel(modelValue: DateRange<D>): D | null;
408409
_onKeydown(event: KeyboardEvent): void;
410+
protected _shouldHandleChangeEvent(change: DateSelectionModelChange<DateRange<D>>): boolean;
409411
ngDoCheck(): void;
410412
ngOnInit(): void;
411413
static ngAcceptInputType_disabled: BooleanInput;
@@ -517,6 +519,7 @@ export declare class MatStartDate<D> extends _MatDateRangeInputBase<D> implement
517519
protected _assignValueToModel(value: D | null): void;
518520
protected _formatValue(value: D | null): void;
519521
protected _getValueFromModel(modelValue: DateRange<D>): D | null;
522+
protected _shouldHandleChangeEvent(change: DateSelectionModelChange<DateRange<D>>): boolean;
520523
getMirrorValue(): string;
521524
ngDoCheck(): void;
522525
ngOnInit(): void;

0 commit comments

Comments
 (0)