fix(calendar): not reacting to min/max boundary changes (#7234)

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.
This commit is contained in:
Kristiyan Kostadinov
2017-09-29 22:06:18 +02:00
committed by Andrew Seguin
parent 6be046261a
commit eb012cc9b7
4 changed files with 85 additions and 5 deletions
+51
View File
@@ -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', () => {
+24 -1
View File
@@ -31,6 +31,9 @@ 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';
@@ -38,6 +41,8 @@ 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';
/**
@@ -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. */
@@ -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 &&
@@ -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)) {
+5 -2
View File
@@ -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';
@@ -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');
}
@@ -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 =
@@ -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. */
+5 -2
View File
@@ -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';
@@ -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');
}
@@ -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);
@@ -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();
}
/**