Skip to content

Commit cd7a1e7

Browse files
committed
feat(calendar): multiview kboard navigation #4282
1 parent 04edfd1 commit cd7a1e7

File tree

7 files changed

+244
-135
lines changed

7 files changed

+244
-135
lines changed

projects/igniteui-angular/src/lib/calendar/calendar-base.ts

+14
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,20 @@ export class IgxCalendarBase implements ControlValueAccessor {
210210
this._specialDates = value;
211211
}
212212

213+
/**
214+
* Sets/gets whether the inactive dates (dates that are out of the current month) will be hidden.
215+
* Default value is `false`.
216+
* ```html
217+
* <igx-calendar [hideInactiveDates] = "true"></igx-calendar>
218+
* ```
219+
* ```typescript
220+
* let hideInactiveDates = this.calendar.hideInactiveDates;
221+
* ```
222+
*/
223+
224+
@Input()
225+
public hideInactiveDates: boolean;
226+
213227
/**
214228
* Emits an event when a date is selected.
215229
* Provides reference the `selectedDates` property.

projects/igniteui-angular/src/lib/calendar/calendar.component.html

+15-14
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
</ng-template>
55

66
<ng-template let-result #defaultMonth >
7-
<ng-container *ngFor="let view of dayViews; let i of index;">
7+
<ng-container *ngFor="let view of dayViews; index as i;">
88
<div>
99
<span tabindex="0" #monthsBtn (keydown)="activeViewYearKB($event)" (click)="activeViewYear()"
1010
class="igx-calendar-picker__date">
11-
{{ formattedMonth(view.viewDate) }}
11+
{{ formattedMonth(getViewDate(i)) }}
1212
</span>
1313
<span tabindex="0" #yearsBtn (keydown)="activeViewDecadeKB($event)" (click)="activeViewDecade()"
1414
class="igx-calendar-picker__date">
15-
{{ formattedYear(view.viewDate) }}
15+
{{ formattedYear(getViewDate(i)) }}
1616
</span>
1717
</div>
1818
</ng-container>
@@ -44,17 +44,18 @@ <h2 class="igx-calendar__header-date">
4444
</div>
4545

4646
<div style="display: flex">
47-
<igx-days-view *ngFor="let view of dayViews; let i of index;" [changeDaysView]="true" #days
48-
[animationAction]="view.monthAction"
49-
[locale]="view.locale"
50-
[value]="view.value"
51-
[viewDate]="view.viewDate"
52-
[weekStart]="view.weekStart"
53-
[formatOptions]="view.formatOptions"
54-
[formatViews]="view.formatViews"
55-
[selection]="view.selection"
56-
[disabledDates]="view.disabledDates"
57-
[specialDates]="view.specialDates"
47+
<igx-days-view *ngFor="let view of dayViews; index as i;" [changeDaysView]="true" #days
48+
[animationAction]="monthAction"
49+
[locale]="locale"
50+
[value]="value"
51+
[viewDate]="viewDate"
52+
[weekStart]="weekStart"
53+
[formatOptions]="formatOptions"
54+
[formatViews]="formatViews"
55+
[selection]="selection"
56+
[disabledDates]="disabledDates"
57+
[specialDates]="specialDates"
58+
[hideInactiveDates]="hideInactiveDates"
5859
(onViewChanged)="viewChanged($event)"
5960
(onDateSelection)="childClicked($event)">
6061
</igx-days-view>

projects/igniteui-angular/src/lib/calendar/calendar.component.ts

+65-49
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import {
88
Input,
99
ViewChild,
1010
ElementRef,
11-
AfterViewInit
11+
AfterViewInit,
12+
ViewChildren,
13+
QueryList
1214
} from '@angular/core';
1315
import { NG_VALUE_ACCESSOR } from '@angular/forms';
1416
import { fadeIn, scaleInCenter } from '../animations/main';
@@ -21,26 +23,16 @@ import { ICalendarDate, monthRange } from './calendar';
2123
import { CalendarView, IgxMonthPickerBase } from './month-picker-base';
2224
import { IgxMonthsViewComponent } from './months-view/months-view.component';
2325
import { IgxYearsViewComponent } from './years-view/years-view.component';
24-
import { IgxDaysViewComponent } from './days-view/days-view.component';
25-
import { DateRangeDescriptor } from '../core/dates';
26+
import { IgxDaysViewComponent, IViewChangedArgs } from './days-view/days-view.component';
2627
import { interval } from 'rxjs';
2728
import { takeUntil, debounce, skipLast, switchMap } from 'rxjs/operators';
2829
import { ScrollMonth } from './calendar-base';
2930

3031
let NEXT_ID = 0;
3132

32-
export interface IDayView {
33-
changeDaysView: boolean;
34-
animationAction: string;
35-
locale: string;
33+
export interface IMonthView {
3634
value: Date | Date[];
3735
viewDate: Date;
38-
weekStart: number;
39-
formatOptions: object;
40-
formatViews: object;
41-
selection: string;
42-
disabledDates: DateRangeDescriptor[];
43-
specialDates: DateRangeDescriptor[];
4436
}
4537

4638
/**
@@ -110,30 +102,31 @@ export class IgxCalendarComponent extends IgxMonthPickerBase implements AfterVie
110102
public vertical = false;
111103

112104
/**
113-
* Sets/gets the number of dayViews duisplayed.
105+
* Sets/gets the number of month views displayed.
114106
* Default value is `1`.
115107
* ```html
116-
* <igx-calendar [vertical] = "true" [daysViewNumber]="2"></igx-calendar>
108+
* <igx-calendar [vertical] = "true" [monthsViewNumber]="2"></igx-calendar>
117109
* ```
118110
* ```typescript
119-
* let daysViewsDisplayed = this.calendar.daysViewNumber;
111+
* let monthViewsDisplayed = this.calendar.monthsViewNumber;
120112
* ```
121113
*/
122114
@Input()
123-
get daysViewNumber() {
124-
return this._daysViewNumber;
115+
get monthsViewNumber() {
116+
return this._monthsViewNumber;
125117
}
126118

127-
set daysViewNumber(val: number) {
128-
this._daysViewNumber = val;
119+
set monthsViewNumber(val: number) {
120+
this._monthsViewNumber = val;
129121

130-
for (let i = 1; i < val; i++) {
131-
const dayView = Object.assign({}, this.defaultDayView);
132-
dayView.value = null;
133-
const nextMonthDate = new Date(dayView.viewDate);
122+
for (let i = 0; i < val; i++) {
123+
const nextMonthDate = new Date(this.viewDate);
134124
nextMonthDate.setMonth(nextMonthDate.getMonth() + i);
135-
dayView.viewDate = nextMonthDate;
136-
this.dayViews.push(dayView);
125+
const monthView: IMonthView = {
126+
value: null,
127+
viewDate: nextMonthDate
128+
};
129+
this.dayViews.push(monthView);
137130
}
138131
}
139132

@@ -201,7 +194,10 @@ export class IgxCalendarComponent extends IgxMonthPickerBase implements AfterVie
201194
* @hidden
202195
*/
203196
@ViewChild('days', { read: IgxDaysViewComponent, static: false })
204-
public daysView: IgxDaysViewComponent;
197+
public daysView = new IgxDaysViewComponent;
198+
199+
@ViewChildren('days', { read: IgxDaysViewComponent })
200+
public monthViews: QueryList<IgxDaysViewComponent>;
205201

206202
/**
207203
* @hidden
@@ -335,32 +331,22 @@ export class IgxCalendarComponent extends IgxMonthPickerBase implements AfterVie
335331
/**
336332
*@hidden
337333
*/
338-
private _daysViewNumber = 1;
339-
340-
/**
341-
*@hidden
342-
*/
343-
private defaultDayView: IDayView = {
344-
changeDaysView: true,
345-
animationAction: this._monthAction,
346-
locale: this.locale,
347-
value: this.value,
348-
viewDate: this.viewDate,
349-
weekStart: this.weekStart,
350-
formatOptions: this.formatOptions,
351-
formatViews: this.formatViews,
352-
selection: this.selection,
353-
disabledDates: this.disabledDates,
354-
specialDates: this.specialDates
355-
};
334+
private _monthsViewNumber = 1;
356335

357336
/**
358337
*@hidden
359338
*/
360-
private dayViews: Array<IDayView> = [this.defaultDayView];
339+
private dayViews = [];
361340

362341
public ngAfterViewInit() {
363342

343+
this.monthViews.forEach((item, index) => {
344+
const prevMonthView = this.getMonthView(index - 1);
345+
const nextMonthView = this.getMonthView(index + 1);
346+
item.nextMonthView = nextMonthView;
347+
item.prevMonthView = prevMonthView;
348+
});
349+
364350
this.startMonthScroll$.pipe(
365351
takeUntil(this.stopMonthScroll$),
366352
switchMap(() => this.daysView.scrollMonth$.pipe(
@@ -400,7 +386,7 @@ export class IgxCalendarComponent extends IgxMonthPickerBase implements AfterVie
400386
*/
401387
public previousMonth(isKeydownTrigger = false) {
402388
this.viewDate = this.calendarModel.timedelta(this.viewDate, 'month', -1);
403-
this.dayViews.forEach((val, index) => {
389+
this.dayViews.forEach((val) => {
404390
val.viewDate = this.calendarModel.timedelta(val.viewDate, 'month', -1);
405391
});
406392
this._monthAction = 'prev';
@@ -415,6 +401,9 @@ export class IgxCalendarComponent extends IgxMonthPickerBase implements AfterVie
415401
*/
416402
public nextMonth(isKeydownTrigger = false) {
417403
this.viewDate = this.calendarModel.timedelta(this.viewDate, 'month', 1);
404+
this.dayViews.forEach((val) => {
405+
val.viewDate = this.calendarModel.timedelta(val.viewDate, 'month', 1);
406+
});
418407
this._monthAction = 'next';
419408

420409
if (this.daysView) {
@@ -518,8 +507,14 @@ export class IgxCalendarComponent extends IgxMonthPickerBase implements AfterVie
518507
/**
519508
* @hidden
520509
*/
521-
public viewChanged(event) {
522-
this.viewDate = this.calendarModel.timedelta(event, 'month', 0);
510+
public viewChanged(event: IViewChangedArgs) {
511+
let date = this.viewDate,
512+
delta = event.delta;
513+
if (event.moveToFirst) {
514+
delta = 0;
515+
date = event.date;
516+
}
517+
this.viewDate = this.calendarModel.timedelta(date, 'month', delta);
523518
}
524519

525520
/**
@@ -570,6 +565,15 @@ export class IgxCalendarComponent extends IgxMonthPickerBase implements AfterVie
570565
this._onChangeCallback(this.selectedDates);
571566
}
572567

568+
/**
569+
* @hidden
570+
*/
571+
public getViewDate(i: number): Date {
572+
const nextMonthDate = new Date(this.viewDate);
573+
nextMonthDate.setMonth(nextMonthDate.getMonth() + i);
574+
return nextMonthDate;
575+
}
576+
573577
/**
574578
* @hidden
575579
*/
@@ -746,4 +750,16 @@ export class IgxCalendarComponent extends IgxMonthPickerBase implements AfterVie
746750
};
747751
return { $implicit: formatObject };
748752
}
753+
754+
/**
755+
* Helper method returning previous/next day views
756+
* @hidden
757+
*/
758+
private getMonthView(index): IgxDaysViewComponent {
759+
if (index === -1 || index === this.monthViews.length ) {
760+
return null;
761+
} else {
762+
return this.monthViews.toArray()[index];
763+
}
764+
}
749765
}

projects/igniteui-angular/src/lib/calendar/days-view/day-item.component.ts

+12
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ export class IgxDayItemComponent {
2929
@Input()
3030
public specialDates: DateRangeDescriptor[];
3131

32+
@Input()
33+
public hideInactiveDates: boolean;
34+
3235
@Output()
3336
public onDateSelection = new EventEmitter<ICalendarDate>();
3437

@@ -73,6 +76,10 @@ export class IgxDayItemComponent {
7376
return this.date.isNextMonth || this.date.isPrevMonth;
7477
}
7578

79+
public get isHidden(): boolean {
80+
return this.hideInactiveDates && this.isInactive;
81+
}
82+
7683
public get isToday(): boolean {
7784
const today = new Date(Date.now());
7885
const date = this.date.date;
@@ -124,6 +131,11 @@ export class IgxDayItemComponent {
124131
return this.isInactive;
125132
}
126133

134+
@HostBinding('class.igx-calendar__date--hidden')
135+
get isHiddenCSS(): boolean {
136+
return this.isHidden;
137+
}
138+
127139
@HostBinding('class.igx-calendar__date--current')
128140
public get isTodayCSS(): boolean {
129141
return this.isToday && !this.selected;

projects/igniteui-angular/src/lib/calendar/days-view/days-view.component.html

+12-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,17 @@
44
</span>
55
</div>
66

7-
<div *ngFor="let week of getCalendarMonth; last as isLast; index as i; trackBy: rowTracker" class="igx-calendar__body-row" [@animateChange]="animationAction" (@animateChange.done)="animationDone($event, isLast)">
8-
<igx-day-item [date]="day" [selection]="selection" [value]="value" [disabledDates]="disabledDates" [specialDates]="specialDates" [outOfRangeDates]="outOfRangeDates" (onDateSelection)="selectDay($event)" *ngFor="let day of week; trackBy: dateTracker">
9-
{{ formattedDate(day.date) }}
7+
<div *ngFor="let week of getCalendarMonth; last as isLast; index as i; trackBy: rowTracker" class="igx-calendar__body-row"
8+
[@animateChange]="animationAction"
9+
(@animateChange.done)="animationDone($event, isLast)">
10+
<igx-day-item [date]="day" *ngFor="let day of week; trackBy: dateTracker"
11+
[selection]="selection"
12+
[value]="value"
13+
[disabledDates]="disabledDates"
14+
[specialDates]="specialDates"
15+
[outOfRangeDates]="outOfRangeDates"
16+
[hideInactiveDates]="hideInactiveDates"
17+
(onDateSelection)="selectDay($event)" >
18+
{{ formattedDate(day.date) }}
1019
</igx-day-item>
1120
</div>

0 commit comments

Comments
 (0)