Skip to content

Commit

Permalink
fix(calendar): not reacting to min/max boundary changes
Browse files Browse the repository at this point in the history
Fixes the calendar not re-rendering when the `minDate`, `maxDate` or `dateFilter` change. The issue was due to the fact that the `minDate`, `maxDate` and `dateFilter` weren't being passed down to the views via `@Input`.

Fixes #7202.
  • Loading branch information
crisbeto committed Sep 29, 2017
1 parent 53c42a4 commit d971c0a
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 5 deletions.
51 changes: 51 additions & 0 deletions src/lib/datepicker/calendar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,57 @@ describe('MatCalendar', () => {

expect(calendarInstance._activeDate).toEqual(new Date(2018, JAN, 1));
});

it('should re-render the month view when the minDate changes', () => {
fixture.detectChanges();
spyOn(calendarInstance.monthView, '_init').and.callThrough();

testComponent.minDate = new Date(2017, NOV, 1);
fixture.detectChanges();

expect(calendarInstance.monthView._init).toHaveBeenCalled();
});

it('should re-render the month view when the maxDate changes', () => {
fixture.detectChanges();
spyOn(calendarInstance.monthView, '_init').and.callThrough();

testComponent.maxDate = new Date(2017, DEC, 1);
fixture.detectChanges();

expect(calendarInstance.monthView._init).toHaveBeenCalled();
});

it('should re-render the year view when the minDate changes', () => {
fixture.detectChanges();
const periodButton =
calendarElement.querySelector('.mat-calendar-period-button') as HTMLElement;
periodButton.click();
fixture.detectChanges();

spyOn(calendarInstance.yearView, '_init').and.callThrough();

testComponent.minDate = new Date(2017, NOV, 1);
fixture.detectChanges();

expect(calendarInstance.yearView._init).toHaveBeenCalled();
});

it('should re-render the year view when the maxDate changes', () => {
fixture.detectChanges();
const periodButton =
calendarElement.querySelector('.mat-calendar-period-button') as HTMLElement;
periodButton.click();
fixture.detectChanges();

spyOn(calendarInstance.yearView, '_init').and.callThrough();

testComponent.maxDate = new Date(2017, DEC, 1);
fixture.detectChanges();

expect(calendarInstance.yearView._init).toHaveBeenCalled();
});

});

describe('calendar with date filter', () => {
Expand Down
25 changes: 24 additions & 1 deletion src/lib/datepicker/calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,18 @@ import {
Optional,
Output,
ViewEncapsulation,
ViewChild,
OnChanges,
SimpleChanges,
} from '@angular/core';
import {DateAdapter, MAT_DATE_FORMATS, MatDateFormats} from '@angular/material/core';
import {first} from 'rxjs/operator/first';
import {Subscription} from 'rxjs/Subscription';
import {coerceDateProperty} from './coerce-date-property';
import {createMissingDateImplError} from './datepicker-errors';
import {MatDatepickerIntl} from './datepicker-intl';
import {MatMonthView} from './month-view';
import {MatYearView} from './year-view';


/**
Expand All @@ -56,7 +61,7 @@ import {MatDatepickerIntl} from './datepicker-intl';
preserveWhitespaces: false,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MatCalendar<D> implements AfterContentInit, OnDestroy {
export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
private _intlChanges: Subscription;

/** A date representing the period (month or year) to start the calendar in. */
Expand Down Expand Up @@ -95,6 +100,12 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy {
/** Emits when any date is selected. */
@Output() userSelection = new EventEmitter<void>();

/** Reference to the current month view component. */
@ViewChild(MatMonthView) monthView: MatMonthView<D>;

/** Reference to the current year view component. */
@ViewChild(MatYearView) yearView: MatYearView<D>;

/** Date filter for the month and year views. */
_dateFilterForViews = (date: D) => {
return !!date &&
Expand Down Expand Up @@ -166,6 +177,18 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy {
this._intlChanges.unsubscribe();
}

ngOnChanges(changes: SimpleChanges) {
const change = changes.minDate || changes.maxDate || changes.dateFilter;

if (change && !change.firstChange) {
const view = this.monthView || this.yearView;

if (view) {
view._init();
}
}
}

/** Handles date selection in the month view. */
_dateSelected(date: D): void {
if (!this._dateAdapter.sameDate(date, this.selected)) {
Expand Down
7 changes: 5 additions & 2 deletions src/lib/datepicker/month-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
Optional,
Output,
ViewEncapsulation,
ChangeDetectorRef,
} from '@angular/core';
import {DateAdapter, MAT_DATE_FORMATS, MatDateFormats} from '@angular/material/core';
import {MatCalendarCell} from './calendar-body';
Expand Down Expand Up @@ -93,7 +94,8 @@ export class MatMonthView<D> implements AfterContentInit {
_weekdays: {long: string, narrow: string}[];

constructor(@Optional() public _dateAdapter: DateAdapter<D>,
@Optional() @Inject(MAT_DATE_FORMATS) private _dateFormats: MatDateFormats) {
@Optional() @Inject(MAT_DATE_FORMATS) private _dateFormats: MatDateFormats,
private _changeDetectorRef: ChangeDetectorRef) {
if (!this._dateAdapter) {
throw createMissingDateImplError('DateAdapter');
}
Expand Down Expand Up @@ -132,7 +134,7 @@ export class MatMonthView<D> implements AfterContentInit {
}

/** Initializes this month view. */
private _init() {
_init() {
this._selectedDate = this._getDateInCurrentMonth(this.selected);
this._todayDate = this._getDateInCurrentMonth(this._dateAdapter.today());
this._monthLabel =
Expand All @@ -146,6 +148,7 @@ export class MatMonthView<D> implements AfterContentInit {
this._dateAdapter.getFirstDayOfWeek()) % DAYS_PER_WEEK;

this._createWeekCells();
this._changeDetectorRef.markForCheck();
}

/** Creates MatCalendarCells for the dates in this month. */
Expand Down
7 changes: 5 additions & 2 deletions src/lib/datepicker/year-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
Optional,
Output,
ViewEncapsulation,
ChangeDetectorRef,
} from '@angular/core';
import {DateAdapter, MAT_DATE_FORMATS, MatDateFormats} from '@angular/material/core';
import {MatCalendarCell} from './calendar-body';
Expand Down Expand Up @@ -79,7 +80,8 @@ export class MatYearView<D> implements AfterContentInit {
_selectedMonth: number | null;

constructor(@Optional() public _dateAdapter: DateAdapter<D>,
@Optional() @Inject(MAT_DATE_FORMATS) private _dateFormats: MatDateFormats) {
@Optional() @Inject(MAT_DATE_FORMATS) private _dateFormats: MatDateFormats,
private _changeDetectorRef: ChangeDetectorRef) {
if (!this._dateAdapter) {
throw createMissingDateImplError('DateAdapter');
}
Expand All @@ -104,7 +106,7 @@ export class MatYearView<D> implements AfterContentInit {
}

/** Initializes this month view. */
private _init() {
_init() {
this._selectedMonth = this._getMonthInCurrentYear(this.selected);
this._todayMonth = this._getMonthInCurrentYear(this._dateAdapter.today());
this._yearLabel = this._dateAdapter.getYearName(this.activeDate);
Expand All @@ -113,6 +115,7 @@ export class MatYearView<D> implements AfterContentInit {
// First row of months only contains 5 elements so we can fit the year label on the same row.
this._months = [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]].map(row => row.map(
month => this._createCellForMonth(month, monthNames[month])));
this._changeDetectorRef.markForCheck();
}

/**
Expand Down

0 comments on commit d971c0a

Please sign in to comment.