Skip to content

Commit c349eba

Browse files
committed
fix(material/datepicker): avoid rerender when min/maxDate changes to different time on the same day
Avoid re-rendering <mat-calendar/> when the [minDate] or [maxDate] Input change to a different time on the same day. In `ngOnChanges`, do not call `init` if the previous and current value for minDate/maxDate are on the same day. This makes #24384 a non-breaking code change. Fixes #24435
1 parent b4058d7 commit c349eba

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

src/material/datepicker/calendar.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,16 @@ describe('MatCalendar', () => {
433433
expect(calendarInstance.monthView._init).toHaveBeenCalled();
434434
});
435435

436+
it('should not re-render the month view when the minDate changes to the same day at a different time', () => {
437+
fixture.detectChanges();
438+
spyOn(calendarInstance.monthView, '_init').and.callThrough();
439+
440+
testComponent.minDate = new Date(2016, JAN, 1, 0, 0, 0, 1);
441+
fixture.detectChanges();
442+
443+
expect(calendarInstance.monthView._init).not.toHaveBeenCalled();
444+
});
445+
436446
it('should re-render the month view when the maxDate changes', () => {
437447
fixture.detectChanges();
438448
spyOn(calendarInstance.monthView, '_init').and.callThrough();
@@ -481,6 +491,25 @@ describe('MatCalendar', () => {
481491
expect(calendarInstance.yearView._init).toHaveBeenCalled();
482492
});
483493

494+
it('should not re-render the year view when the maxDate changes to the same day at a different time', () => {
495+
fixture.detectChanges();
496+
const periodButton = calendarElement.querySelector(
497+
'.mat-calendar-period-button',
498+
) as HTMLElement;
499+
periodButton.click();
500+
fixture.detectChanges();
501+
502+
(calendarElement.querySelector('.mat-calendar-body-active') as HTMLElement).click();
503+
fixture.detectChanges();
504+
505+
spyOn(calendarInstance.yearView, '_init').and.callThrough();
506+
507+
testComponent.maxDate = new Date(2018, JAN, 1, 0, 0, 1, 0);
508+
fixture.detectChanges();
509+
510+
expect(calendarInstance.yearView._init).not.toHaveBeenCalled();
511+
});
512+
484513
it('should re-render the multi-year view when the minDate changes', () => {
485514
fixture.detectChanges();
486515
const periodButton = calendarElement.querySelector(

src/material/datepicker/calendar.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,27 @@ export class MatCalendar<D> implements AfterContentInit, AfterViewChecked, OnDes
393393
}
394394

395395
ngOnChanges(changes: SimpleChanges) {
396-
const change = changes['minDate'] || changes['maxDate'] || changes['dateFilter'];
396+
let change = undefined;
397+
398+
for (let key in changes) {
399+
switch (key) {
400+
case 'minDate':
401+
case 'maxDate':
402+
// Ignore date changes that are at a different time on the same day. This fixes issues
403+
// where the calendar re-renders when there's no meaning change to [minDate] or [maxDate]
404+
// (#24435).
405+
if (!this._dateAdapter.sameDate(changes[key].previousValue, changes[key].currentValue)) {
406+
change = changes[key];
407+
}
408+
break;
409+
case 'dateFilter':
410+
change = changes[key];
411+
}
412+
413+
if (change) {
414+
break;
415+
}
416+
}
397417

398418
if (change && !change.firstChange) {
399419
const view = this._getCurrentViewComponent();

0 commit comments

Comments
 (0)