Skip to content

Commit 5e34de2

Browse files
authored
fix(datepicker): don't call date filter function if date is out of bounds (#18419)
Doesn't call the `dateFilter` function for date is before the minimum or after the maximum in the month view. We were already doing this for the rest of the views, but I added some tests so we have coverage for it. Fixes #18411.
1 parent 004eeb8 commit 5e34de2

File tree

4 files changed

+100
-36
lines changed

4 files changed

+100
-36
lines changed

src/material/datepicker/month-view.spec.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -292,22 +292,37 @@ describe('MatMonthView', () => {
292292
});
293293

294294
describe('month view with date filter', () => {
295-
let fixture: ComponentFixture<MonthViewWithDateFilter>;
296-
let monthViewNativeElement: Element;
295+
it('should disable filtered dates', () => {
296+
const fixture = TestBed.createComponent(MonthViewWithDateFilter);
297+
fixture.detectChanges();
297298

298-
beforeEach(() => {
299-
fixture = TestBed.createComponent(MonthViewWithDateFilter);
299+
let cells = fixture.nativeElement.querySelectorAll('.mat-calendar-body-cell');
300+
expect(cells[0].classList).toContain('mat-calendar-body-disabled');
301+
expect(cells[1].classList).not.toContain('mat-calendar-body-disabled');
302+
});
303+
304+
it('should not call the date filter function if the date is before the min date', () => {
305+
const fixture = TestBed.createComponent(MonthViewWithDateFilter);
306+
const activeDate = fixture.componentInstance.activeDate;
307+
const spy = spyOn(fixture.componentInstance, 'dateFilter').and.callThrough();
308+
fixture.componentInstance.minDate =
309+
new Date(activeDate.getFullYear() + 1, activeDate.getMonth(), activeDate.getDate());
300310
fixture.detectChanges();
301311

302-
let monthViewDebugElement = fixture.debugElement.query(By.directive(MatMonthView))!;
303-
monthViewNativeElement = monthViewDebugElement.nativeElement;
312+
expect(spy).not.toHaveBeenCalled();
304313
});
305314

306-
it('should disable filtered dates', () => {
307-
let cells = monthViewNativeElement.querySelectorAll('.mat-calendar-body-cell');
308-
expect(cells[0].classList).toContain('mat-calendar-body-disabled');
309-
expect(cells[1].classList).not.toContain('mat-calendar-body-disabled');
315+
it('should not call the date filter function if the date is after the max date', () => {
316+
const fixture = TestBed.createComponent(MonthViewWithDateFilter);
317+
const activeDate = fixture.componentInstance.activeDate;
318+
const spy = spyOn(fixture.componentInstance, 'dateFilter').and.callThrough();
319+
fixture.componentInstance.maxDate =
320+
new Date(activeDate.getFullYear() - 1, activeDate.getMonth(), activeDate.getDate());
321+
fixture.detectChanges();
322+
323+
expect(spy).not.toHaveBeenCalled();
310324
});
325+
311326
});
312327

313328
describe('month view with custom date classes', () => {
@@ -342,10 +357,17 @@ class StandardMonthView {
342357

343358

344359
@Component({
345-
template: `<mat-month-view [activeDate]="activeDate" [dateFilter]="dateFilter"></mat-month-view>`
360+
template: `
361+
<mat-month-view
362+
[activeDate]="activeDate"
363+
[dateFilter]="dateFilter"
364+
[minDate]="minDate"
365+
[maxDate]="maxDate"></mat-month-view>`
346366
})
347367
class MonthViewWithDateFilter {
348368
activeDate = new Date(2017, JAN, 1);
369+
minDate: Date | null = null;
370+
maxDate: Date | null = null;
349371
dateFilter(date: Date) {
350372
return date.getDate() % 2 == 0;
351373
}

src/material/datepicker/month-view.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,9 +300,9 @@ export class MatMonthView<D> implements AfterContentInit, OnDestroy {
300300
/** Date filter for the month */
301301
private _shouldEnableDate(date: D): boolean {
302302
return !!date &&
303-
(!this.dateFilter || this.dateFilter(date)) &&
304303
(!this.minDate || this._dateAdapter.compareDate(date, this.minDate) >= 0) &&
305-
(!this.maxDate || this._dateAdapter.compareDate(date, this.maxDate) <= 0);
304+
(!this.maxDate || this._dateAdapter.compareDate(date, this.maxDate) <= 0) &&
305+
(!this.dateFilter || this.dateFilter(date));
306306
}
307307

308308
/**

src/material/datepicker/multi-year-view.spec.ts

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -231,22 +231,37 @@ describe('MatMultiYearView', () => {
231231
});
232232

233233
describe('multi year view with date filter', () => {
234-
let fixture: ComponentFixture<MultiYearViewWithDateFilter>;
235-
let multiYearViewNativeElement: Element;
234+
it('should disable years with no enabled days', () => {
235+
const fixture = TestBed.createComponent(MultiYearViewWithDateFilter);
236+
fixture.detectChanges();
236237

237-
beforeEach(() => {
238-
fixture = TestBed.createComponent(MultiYearViewWithDateFilter);
238+
const cells = fixture.nativeElement.querySelectorAll('.mat-calendar-body-cell');
239+
expect(cells[0].classList).not.toContain('mat-calendar-body-disabled');
240+
expect(cells[1].classList).toContain('mat-calendar-body-disabled');
241+
});
242+
243+
it('should not call the date filter function if the date is before the min date', () => {
244+
const fixture = TestBed.createComponent(MultiYearViewWithDateFilter);
245+
const activeDate = fixture.componentInstance.activeDate;
246+
const spy = spyOn(fixture.componentInstance, 'dateFilter').and.callThrough();
247+
fixture.componentInstance.minDate =
248+
new Date(activeDate.getFullYear() + 1, activeDate.getMonth(), activeDate.getDate());
239249
fixture.detectChanges();
240250

241-
const multiYearViewDebugElement = fixture.debugElement.query(By.directive(MatMultiYearView))!;
242-
multiYearViewNativeElement = multiYearViewDebugElement.nativeElement;
251+
expect(spy).not.toHaveBeenCalled();
243252
});
244253

245-
it('should disablex years with no enabled days', () => {
246-
const cells = multiYearViewNativeElement.querySelectorAll('.mat-calendar-body-cell');
247-
expect(cells[0].classList).not.toContain('mat-calendar-body-disabled');
248-
expect(cells[1].classList).toContain('mat-calendar-body-disabled');
254+
it('should not call the date filter function if the date is after the max date', () => {
255+
const fixture = TestBed.createComponent(MultiYearViewWithDateFilter);
256+
const activeDate = fixture.componentInstance.activeDate;
257+
const spy = spyOn(fixture.componentInstance, 'dateFilter').and.callThrough();
258+
fixture.componentInstance.maxDate =
259+
new Date(activeDate.getFullYear() - 1, activeDate.getMonth(), activeDate.getDate());
260+
fixture.detectChanges();
261+
262+
expect(spy).not.toHaveBeenCalled();
249263
});
264+
250265
});
251266

252267
describe('multi year view with minDate only', () => {
@@ -345,12 +360,17 @@ class StandardMultiYearView {
345360

346361
@Component({
347362
template: `
348-
<mat-multi-year-view [(activeDate)]="activeDate" [dateFilter]="dateFilter">
349-
</mat-multi-year-view>
363+
<mat-multi-year-view
364+
[(activeDate)]="activeDate"
365+
[dateFilter]="dateFilter"
366+
[minDate]="minDate"
367+
[maxDate]="maxDate"></mat-multi-year-view>
350368
`
351369
})
352370
class MultiYearViewWithDateFilter {
353371
activeDate = new Date(2017, JAN, 1);
372+
minDate: Date | null = null;
373+
maxDate: Date | null = null;
354374
dateFilter(date: Date) {
355375
return date.getFullYear() !== 2017;
356376
}

src/material/datepicker/year-view.spec.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -297,22 +297,37 @@ describe('MatYearView', () => {
297297
});
298298

299299
describe('year view with date filter', () => {
300-
let fixture: ComponentFixture<YearViewWithDateFilter>;
301-
let yearViewNativeElement: Element;
300+
it('should disable months with no enabled days', () => {
301+
const fixture = TestBed.createComponent(YearViewWithDateFilter);
302+
fixture.detectChanges();
302303

303-
beforeEach(() => {
304-
fixture = TestBed.createComponent(YearViewWithDateFilter);
304+
const cells = fixture.nativeElement.querySelectorAll('.mat-calendar-body-cell');
305+
expect(cells[0].classList).not.toContain('mat-calendar-body-disabled');
306+
expect(cells[1].classList).toContain('mat-calendar-body-disabled');
307+
});
308+
309+
it('should not call the date filter function if the date is before the min date', () => {
310+
const fixture = TestBed.createComponent(YearViewWithDateFilter);
311+
const activeDate = fixture.componentInstance.activeDate;
312+
const spy = spyOn(fixture.componentInstance, 'dateFilter').and.callThrough();
313+
fixture.componentInstance.minDate =
314+
new Date(activeDate.getFullYear() + 1, activeDate.getMonth(), activeDate.getDate());
305315
fixture.detectChanges();
306316

307-
const yearViewDebugElement = fixture.debugElement.query(By.directive(MatYearView))!;
308-
yearViewNativeElement = yearViewDebugElement.nativeElement;
317+
expect(spy).not.toHaveBeenCalled();
309318
});
310319

311-
it('should disable months with no enabled days', () => {
312-
const cells = yearViewNativeElement.querySelectorAll('.mat-calendar-body-cell');
313-
expect(cells[0].classList).not.toContain('mat-calendar-body-disabled');
314-
expect(cells[1].classList).toContain('mat-calendar-body-disabled');
320+
it('should not call the date filter function if the date is after the max date', () => {
321+
const fixture = TestBed.createComponent(YearViewWithDateFilter);
322+
const activeDate = fixture.componentInstance.activeDate;
323+
const spy = spyOn(fixture.componentInstance, 'dateFilter').and.callThrough();
324+
fixture.componentInstance.maxDate =
325+
new Date(activeDate.getFullYear() - 1, activeDate.getMonth(), activeDate.getDate());
326+
fixture.detectChanges();
327+
328+
expect(spy).not.toHaveBeenCalled();
315329
});
330+
316331
});
317332
});
318333

@@ -332,10 +347,17 @@ class StandardYearView {
332347

333348

334349
@Component({
335-
template: `<mat-year-view [activeDate]="activeDate" [dateFilter]="dateFilter"></mat-year-view>`
350+
template: `
351+
<mat-year-view
352+
[activeDate]="activeDate"
353+
[dateFilter]="dateFilter"
354+
[minDate]="minDate"
355+
[maxDate]="maxDate"></mat-year-view>`
336356
})
337357
class YearViewWithDateFilter {
338358
activeDate = new Date(2017, JAN, 1);
359+
minDate: Date | null = null;
360+
maxDate: Date | null = null;
339361
dateFilter(date: Date) {
340362
if (date.getMonth() == JAN) {
341363
return date.getDate() == 10;

0 commit comments

Comments
 (0)