Skip to content

Commit 4501b25

Browse files
zarendandrewseguin
authored andcommitted
fix(material/datepicker): avoid rerender when min/maxDate changes to different time on the same day (#24434)
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 (cherry picked from commit 6f9743c)
1 parent ca30f42 commit 4501b25

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

src/material/datepicker/calendar.spec.ts

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

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

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

src/material/datepicker/calendar.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
OnDestroy,
2222
Optional,
2323
Output,
24+
SimpleChange,
2425
SimpleChanges,
2526
ViewChild,
2627
ViewEncapsulation,
@@ -393,7 +394,21 @@ export class MatCalendar<D> implements AfterContentInit, AfterViewChecked, OnDes
393394
}
394395

395396
ngOnChanges(changes: SimpleChanges) {
396-
const change = changes['minDate'] || changes['maxDate'] || changes['dateFilter'];
397+
// Ignore date changes that are at a different time on the same day. This fixes issues where
398+
// the calendar re-renders when there is no meaningful change to [minDate] or [maxDate]
399+
// (#24435).
400+
const minDateChange: SimpleChange | undefined =
401+
changes['minDate'] &&
402+
!this._dateAdapter.sameDate(changes['minDate'].previousValue, changes['minDate'].currentValue)
403+
? changes['minDate']
404+
: undefined;
405+
const maxDateChange: SimpleChange | undefined =
406+
changes['maxDate'] &&
407+
!this._dateAdapter.sameDate(changes['maxDate'].previousValue, changes['maxDate'].currentValue)
408+
? changes['maxDate']
409+
: undefined;
410+
411+
const change = minDateChange || maxDateChange || changes['dateFilter'];
397412

398413
if (change && !change.firstChange) {
399414
const view = this._getCurrentViewComponent();

0 commit comments

Comments
 (0)