Skip to content

Commit

Permalink
fix(material/datepicker): Only update selection when value changed (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mcalmus committed Apr 27, 2021
1 parent 7cc42f5 commit df28ffc
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 3 deletions.
20 changes: 20 additions & 0 deletions src/material/datepicker/date-range-input-parts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,16 @@ export class MatStartDate<D> extends _MatDateRangeInputBase<D> implements
return modelValue.start;
}

protected _shouldHandleChangeEvent(change: DateSelectionModelChange<DateRange<D>>): boolean {
if (!super._shouldHandleChangeEvent(change)) {
return false;
} else {
return !change.oldValue?.start ? !!change.selection.start :
!change.selection.start ||
!!this._dateAdapter.compareDate(change.oldValue.start, change.selection.start);
}
}

protected _assignValueToModel(value: D | null) {
if (this._model) {
const range = new DateRange(value, this._model.selection.end);
Expand Down Expand Up @@ -365,6 +375,16 @@ export class MatEndDate<D> extends _MatDateRangeInputBase<D> implements
return modelValue.end;
}

protected _shouldHandleChangeEvent(change: DateSelectionModelChange<DateRange<D>>): boolean {
if (!super._shouldHandleChangeEvent(change)) {
return false;
} else {
return !change.oldValue?.end ? !!change.selection.end :
!change.selection.end ||
!!this._dateAdapter.compareDate(change.oldValue.end, change.selection.end);
}
}

protected _assignValueToModel(value: D | null) {
if (this._model) {
const range = new DateRange(this._model.selection.start, value);
Expand Down
74 changes: 72 additions & 2 deletions src/material/datepicker/date-range-input.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,60 @@ describe('MatDateRangeInput', () => {
expect(endInput.errorStateMatcher).toBe(matcher);
});


it('should only update model for input that changed', fakeAsync(() => {
const fixture = createComponent(RangePickerNgModel);

fixture.detectChanges();
tick();

expect(fixture.componentInstance.startDateModelChangeCount).toBe(0);
expect(fixture.componentInstance.endDateModelChangeCount).toBe(0);

fixture.componentInstance.rangePicker.open();
fixture.detectChanges();
tick();

const fromDate = new Date(2020, 0, 1);
const toDate = new Date(2020, 0, 2);
fixture.componentInstance.rangePicker.select(fromDate);
fixture.detectChanges();
tick();

expect(fixture.componentInstance.startDateModelChangeCount).toBe(1, 'Start Date set once');
expect(fixture.componentInstance.endDateModelChangeCount).toBe(0, 'End Date not set');

fixture.componentInstance.rangePicker.select(toDate);
fixture.detectChanges();
tick();

expect(fixture.componentInstance.startDateModelChangeCount).toBe(1,
'Start Date unchanged (set once)');
expect(fixture.componentInstance.endDateModelChangeCount).toBe(1, 'End Date set once');

fixture.componentInstance.rangePicker.open();
fixture.detectChanges();
tick();

const fromDate2 = new Date(2021, 0, 1);
const toDate2 = new Date(2021, 0, 2);
fixture.componentInstance.rangePicker.select(fromDate2);
fixture.detectChanges();
tick();

expect(fixture.componentInstance.startDateModelChangeCount).toBe(2, 'Start Date set twice');
expect(fixture.componentInstance.endDateModelChangeCount).toBe(2,
'End Date set twice (nulled)');

fixture.componentInstance.rangePicker.select(toDate2);
fixture.detectChanges();
tick();

expect(fixture.componentInstance.startDateModelChangeCount).toBe(2,
'Start Date unchanged (set twice)');
expect(fixture.componentInstance.endDateModelChangeCount).toBe(3, 'End date set three times');
}));

});

@Component({
Expand Down Expand Up @@ -959,8 +1013,24 @@ class RangePickerNgModel {
@ViewChild(MatStartDate, {read: ElementRef}) startInput: ElementRef<HTMLInputElement>;
@ViewChild(MatEndDate, {read: ElementRef}) endInput: ElementRef<HTMLInputElement>;
@ViewChild(MatDateRangePicker) rangePicker: MatDateRangePicker<Date>;
start: Date | null = null;
end: Date | null = null;
private _start: Date|null = null;
get start(): Date|null {
return this._start;
}
set start(aStart: Date|null) {
this.startDateModelChangeCount++;
this._start = aStart;
}
private _end: Date|null = null;
get end(): Date|null {
return this._end;
}
set end(anEnd: Date|null) {
this.endDateModelChangeCount++;
this._end = anEnd;
}
startDateModelChangeCount = 0;
endDateModelChangeCount = 0;
}


Expand Down
6 changes: 5 additions & 1 deletion src/material/datepicker/date-selection-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export interface DateSelectionModelChange<S> {

/** Object that triggered the change. */
source: unknown;

/** Previous value */
oldValue?: S;
}

/**
Expand Down Expand Up @@ -69,8 +72,9 @@ export abstract class MatDateSelectionModel<S, D = ExtractDateTypeFromSelection<
* @param source Object that triggered the selection change.
*/
updateSelection(value: S, source: unknown) {
const oldValue = (this as {selection: S}).selection;
(this as {selection: S}).selection = value;
this._selectionChanged.next({selection: value, source});
this._selectionChanged.next({selection: value, source, oldValue});
}

ngOnDestroy() {
Expand Down
3 changes: 3 additions & 0 deletions tools/public_api_guard/material/datepicker.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export declare class DateRange<D> {
}

export interface DateSelectionModelChange<S> {
oldValue?: S;
selection: S;
source: unknown;
}
Expand Down Expand Up @@ -405,6 +406,7 @@ export declare class MatEndDate<D> extends _MatDateRangeInputBase<D> implements
protected _assignValueToModel(value: D | null): void;
protected _getValueFromModel(modelValue: DateRange<D>): D | null;
_onKeydown(event: KeyboardEvent): void;
protected _shouldHandleChangeEvent(change: DateSelectionModelChange<DateRange<D>>): boolean;
ngDoCheck(): void;
ngOnInit(): void;
static ngAcceptInputType_disabled: BooleanInput;
Expand Down Expand Up @@ -516,6 +518,7 @@ export declare class MatStartDate<D> extends _MatDateRangeInputBase<D> implement
protected _assignValueToModel(value: D | null): void;
protected _formatValue(value: D | null): void;
protected _getValueFromModel(modelValue: DateRange<D>): D | null;
protected _shouldHandleChangeEvent(change: DateSelectionModelChange<DateRange<D>>): boolean;
getMirrorValue(): string;
ngDoCheck(): void;
ngOnInit(): void;
Expand Down

0 comments on commit df28ffc

Please sign in to comment.