9
9
import { ComponentPortal , ComponentType , Portal } from '@angular/cdk/portal' ;
10
10
import {
11
11
AfterContentInit ,
12
+ AfterViewChecked ,
12
13
ChangeDetectionStrategy ,
13
14
ChangeDetectorRef ,
14
15
Component ,
@@ -32,6 +33,12 @@ import {MatMonthView} from './month-view';
32
33
import { MatMultiYearView , yearsPerPage } from './multi-year-view' ;
33
34
import { MatYearView } from './year-view' ;
34
35
36
+ /**
37
+ * Possible views for the calendar.
38
+ * @docs -private
39
+ */
40
+ export type MatCalendarView = 'month' | 'year' | 'multi-year' ;
41
+
35
42
/** Default header for MatCalendar */
36
43
@Component ( {
37
44
moduleId : module . id ,
@@ -162,7 +169,7 @@ export class MatCalendarHeader<D> {
162
169
encapsulation : ViewEncapsulation . None ,
163
170
changeDetection : ChangeDetectionStrategy . OnPush ,
164
171
} )
165
- export class MatCalendar < D > implements AfterContentInit , OnDestroy , OnChanges {
172
+ export class MatCalendar < D > implements AfterContentInit , AfterViewChecked , OnDestroy , OnChanges {
166
173
/** An input indicating the type of the header component, if set. */
167
174
@Input ( ) headerComponent : ComponentType < any > ;
168
175
@@ -171,6 +178,13 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
171
178
172
179
private _intlChanges : Subscription ;
173
180
181
+ /**
182
+ * Used for scheduling that focus should be moved to the active cell on the next tick.
183
+ * We need to schedule it, rather than do it immediately, because we have to wait
184
+ * for Angular to re-evaluate the view children.
185
+ */
186
+ private _moveFocusOnNextTick = false ;
187
+
174
188
/** A date representing the period (month or year) to start the calendar in. */
175
189
@Input ( )
176
190
get startAt ( ) : D | null { return this . _startAt ; }
@@ -180,7 +194,7 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
180
194
private _startAt : D | null ;
181
195
182
196
/** Whether the calendar should be started in month or year view. */
183
- @Input ( ) startView : 'month' | 'year' | 'multi-year' = 'month' ;
197
+ @Input ( ) startView : MatCalendarView = 'month' ;
184
198
185
199
/** The currently selected date. */
186
200
@Input ( )
@@ -248,7 +262,12 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
248
262
private _clampedActiveDate : D ;
249
263
250
264
/** Whether the calendar is in month view. */
251
- currentView : 'month' | 'year' | 'multi-year' ;
265
+ get currentView ( ) : MatCalendarView { return this . _currentView ; }
266
+ set currentView ( value : MatCalendarView ) {
267
+ this . _currentView = value ;
268
+ this . _moveFocusOnNextTick = true ;
269
+ }
270
+ private _currentView : MatCalendarView ;
252
271
253
272
/**
254
273
* Emits whenever there is a state change that the header may need to respond to.
@@ -276,9 +295,17 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
276
295
277
296
ngAfterContentInit ( ) {
278
297
this . _calendarHeaderPortal = new ComponentPortal ( this . headerComponent || MatCalendarHeader ) ;
279
-
280
298
this . activeDate = this . startAt || this . _dateAdapter . today ( ) ;
281
- this . currentView = this . startView ;
299
+
300
+ // Assign to the private property since we don't want to move focus on init.
301
+ this . _currentView = this . startView ;
302
+ }
303
+
304
+ ngAfterViewChecked ( ) {
305
+ if ( this . _moveFocusOnNextTick ) {
306
+ this . _moveFocusOnNextTick = false ;
307
+ this . focusActiveCell ( ) ;
308
+ }
282
309
}
283
310
284
311
ngOnDestroy ( ) {
@@ -290,7 +317,7 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
290
317
const change = changes . minDate || changes . maxDate || changes . dateFilter ;
291
318
292
319
if ( change && ! change . firstChange ) {
293
- const view = this . monthView || this . yearView || this . multiYearView ;
320
+ const view = this . _getCurrentViewComponent ( ) ;
294
321
295
322
if ( view ) {
296
323
view . _init ( ) ;
@@ -300,6 +327,10 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
300
327
this . stateChanges . next ( ) ;
301
328
}
302
329
330
+ focusActiveCell ( ) {
331
+ this . _getCurrentViewComponent ( ) . _focusActiveCell ( ) ;
332
+ }
333
+
303
334
/** Handles date selection in the month view. */
304
335
_dateSelected ( date : D ) : void {
305
336
if ( ! this . _dateAdapter . sameDate ( date , this . selected ) ) {
@@ -334,4 +365,9 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
334
365
private _getValidDateOrNull ( obj : any ) : D | null {
335
366
return ( this . _dateAdapter . isDateInstance ( obj ) && this . _dateAdapter . isValid ( obj ) ) ? obj : null ;
336
367
}
368
+
369
+ /** Returns the component instance that corresponds to the current calendar view. */
370
+ private _getCurrentViewComponent ( ) {
371
+ return this . monthView || this . yearView || this . multiYearView ;
372
+ }
337
373
}
0 commit comments