Skip to content

Commit d514513

Browse files
committed
feat(calendar): emit events on user actions #7039
1 parent 0f46840 commit d514513

File tree

11 files changed

+139
-206
lines changed

11 files changed

+139
-206
lines changed

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

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ControlValueAccessor } from '@angular/forms';
44
import { DateRangeDescriptor } from '../core/dates';
55
import { Subject } from 'rxjs';
66
import { isDate } from '../core/utils';
7+
import { CalendarView } from './month-picker-base';
78

89
/**
910
* Sets the selction type - single, multi or range.
@@ -20,6 +21,11 @@ export enum ScrollMonth {
2021
NONE = 'none'
2122
}
2223

24+
export interface IViewDateChangeEventArgs {
25+
previousValue: Date;
26+
currentValue: Date;
27+
}
28+
2329
/** @hidden @internal */
2430
@Directive({
2531
selector: '[igxCalendarBase]',
@@ -168,7 +174,8 @@ export class IgxCalendarBaseDirective implements ControlValueAccessor {
168174
* Sets the date that will be presented in the default view when the component renders.
169175
*/
170176
public set viewDate(value: Date) {
171-
this._viewDate = this.getDateOnly(value);
177+
const date = this.getDateOnly(value).setDate(1);
178+
this._viewDate = new Date(date);
172179
}
173180

174181
/**
@@ -240,6 +247,34 @@ export class IgxCalendarBaseDirective implements ControlValueAccessor {
240247
@Output()
241248
public onSelection = new EventEmitter<Date | Date[]>();
242249

250+
/**
251+
* Emits an event when the month in view is changed.
252+
* ```html
253+
* <igx-calendar (onViewDateChanged)="viewDateChanged($event)"></igx-calendar>
254+
* ```
255+
* ```typescript
256+
* public viewDateChanged(event: IViewDateChangeEventArgs) {
257+
* let newDate = event.newViewDate;
258+
* }
259+
* ```
260+
*/
261+
@Output()
262+
public onViewDateChanged = new EventEmitter<IViewDateChangeEventArgs>();
263+
264+
/**
265+
* Emits an event when the active view is changed.
266+
* ```html
267+
* <igx-calendar (onActiveViewChanged)="activeViewChanged($event)"></igx-calendar>
268+
* ```
269+
* ```typescript
270+
* public activeViewChanged(event: CalendarView) {
271+
* let activeView = event;
272+
* }
273+
* ```
274+
*/
275+
@Output()
276+
public onActiveViewChanged = new EventEmitter<CalendarView>();
277+
243278
/**
244279
* @hidden
245280
*/

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,8 @@ describe('IgxCalendar - ', () => {
252252
expect(calendar.formatOptions).toEqual(jasmine.objectContaining(defaultOptions));
253253
expect(calendar.formatViews).toEqual(jasmine.objectContaining(defaultViews));
254254
expect(headerYear.nativeElement.textContent.trim()).toMatch('2018');
255-
expect(headerWeekday.nativeElement.textContent.trim()).toMatch('Mon');
256-
expect(headerDate.nativeElement.textContent.trim()).toMatch('Sep 17');
255+
expect(headerWeekday.nativeElement.textContent.trim()).toMatch('Sat');
256+
expect(headerDate.nativeElement.textContent.trim()).toMatch('Sep 1');
257257
expect(bodyYear.nativeElement.textContent.trim()).toMatch('2018');
258258
expect(bodyMonth.nativeElement.textContent.trim()).toMatch('Sep');
259259

@@ -267,8 +267,8 @@ describe('IgxCalendar - ', () => {
267267
expect(calendar.formatOptions).toEqual(jasmine.objectContaining(Object.assign(defaultOptions, formatOptions)));
268268
expect(calendar.formatViews).toEqual(jasmine.objectContaining(Object.assign(defaultViews, formatViews)));
269269
expect(headerYear.nativeElement.textContent.trim()).toMatch('18');
270-
expect(headerWeekday.nativeElement.textContent.trim()).toMatch('Mon');
271-
expect(headerDate.nativeElement.textContent.trim()).toMatch('September 17');
270+
expect(headerWeekday.nativeElement.textContent.trim()).toMatch('Sat');
271+
expect(headerDate.nativeElement.textContent.trim()).toMatch('September 1');
272272
expect(bodyYear.nativeElement.textContent.trim()).toMatch('18');
273273
expect(bodyMonth.nativeElement.textContent.trim()).toMatch('September');
274274

@@ -283,8 +283,8 @@ describe('IgxCalendar - ', () => {
283283
expect(calendar.formatOptions).toEqual(jasmine.objectContaining(Object.assign(defaultOptions, formatOptions)));
284284
expect(calendar.formatViews).toEqual(jasmine.objectContaining(Object.assign(defaultViews, formatViews)));
285285
expect(headerYear.nativeElement.textContent.trim()).toMatch('2018');
286-
expect(headerWeekday.nativeElement.textContent.trim()).toMatch('Mon');
287-
expect(headerDate.nativeElement.textContent.trim()).toMatch('September 17');
286+
expect(headerWeekday.nativeElement.textContent.trim()).toMatch('Sat');
287+
expect(headerDate.nativeElement.textContent.trim()).toMatch('September 1');
288288
expect(bodyYear.nativeElement.textContent.trim()).toMatch('2018');
289289
expect(bodyMonth.nativeElement.textContent.trim()).toMatch('8');
290290
});
@@ -305,8 +305,8 @@ describe('IgxCalendar - ', () => {
305305
fixture.detectChanges();
306306

307307
expect(headerYear.nativeElement.textContent.trim()).toMatch('2018');
308-
expect(headerWeekday.nativeElement.textContent.trim()).toMatch('Mon');
309-
expect(headerDate.nativeElement.textContent.trim()).toMatch('Sep 17');
308+
expect(headerWeekday.nativeElement.textContent.trim()).toMatch('Sat');
309+
expect(headerDate.nativeElement.textContent.trim()).toMatch('Sep 1');
310310
expect(bodyYear.nativeElement.textContent.trim()).toMatch('2018');
311311
expect(bodyMonth.nativeElement.textContent.trim()).toMatch('Sep');
312312
expect(bodyWeekday.nativeElement.textContent.trim()).toMatch('Sun');
@@ -319,8 +319,8 @@ describe('IgxCalendar - ', () => {
319319
bodyWeekday = dom.query(By.css(HelperTestFunctions.WEEKSTART_LABEL_CSSCLASS));
320320
expect(calendar.locale).toEqual(locale);
321321
expect(headerYear.nativeElement.textContent.trim()).toMatch('18');
322-
expect(headerWeekday.nativeElement.textContent.trim()).toMatch('lun.,');
323-
expect(headerDate.nativeElement.textContent.trim()).toMatch('17 sept.');
322+
expect(headerWeekday.nativeElement.textContent.trim()).toMatch('sam.,');
323+
expect(headerDate.nativeElement.textContent.trim()).toMatch('1 sept.');
324324
expect(bodyYear.nativeElement.textContent.trim()).toMatch('18');
325325
expect(bodyMonth.nativeElement.textContent.trim()).toMatch('sept.');
326326
expect(bodyWeekday.nativeElement.textContent.trim()).toMatch('Dim.');

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,9 +466,13 @@ export class IgxCalendarComponent extends IgxMonthPickerBaseDirective implements
466466
* @internal
467467
*/
468468
public previousMonth(isKeydownTrigger = false) {
469+
const previousValue = this.viewDate;
469470
this.viewDate = this.calendarModel.getPrevMonth(this.viewDate);
470471
this.animationAction = ScrollMonth.PREV;
471472
this.isKeydownTrigger = isKeydownTrigger;
473+
requestAnimationFrame(() => {
474+
this.onViewDateChanged.emit({ previousValue, currentValue: this.viewDate });
475+
});
472476
}
473477

474478
/**
@@ -478,9 +482,13 @@ export class IgxCalendarComponent extends IgxMonthPickerBaseDirective implements
478482
* @internal
479483
*/
480484
public nextMonth(isKeydownTrigger = false) {
485+
const previousValue = this.viewDate;
481486
this.viewDate = this.calendarModel.getNextMonth(this.viewDate);
482487
this.animationAction = ScrollMonth.NEXT;
483488
this.isKeydownTrigger = isKeydownTrigger;
489+
requestAnimationFrame(() => {
490+
this.onViewDateChanged.emit({ previousValue, currentValue: this.viewDate });
491+
});
484492
}
485493

486494
/**
@@ -609,7 +617,9 @@ export class IgxCalendarComponent extends IgxMonthPickerBaseDirective implements
609617
if (day) {
610618
this.daysView.daysNavService.focusNextDate(day.nativeElement, args.key, true);
611619
}
620+
this.onViewDateChanged.emit({previousValue, currentValue: this.viewDate});
612621
};
622+
const previousValue = this.viewDate;
613623
this.viewDate = this.nextDate;
614624
}
615625

@@ -618,12 +628,15 @@ export class IgxCalendarComponent extends IgxMonthPickerBaseDirective implements
618628
* @intenal
619629
*/
620630
public changeMonth(event: Date) {
631+
const previousValue = this.viewDate;
621632
this.viewDate = this.calendarModel.getFirstViewDate(event, 'month', this.activeViewIdx);
622633
this.activeView = CalendarView.DEFAULT;
623634

624635
requestAnimationFrame(() => {
625636
const elem = this.monthsBtns.find((e: ElementRef, idx: number) => idx === this.activeViewIdx);
626637
if (elem) { elem.nativeElement.focus(); }
638+
this.onViewDateChanged.emit({previousValue, currentValue: this.viewDate});
639+
this.onActiveViewChanged.emit(this.activeView);
627640
});
628641
}
629642

@@ -637,6 +650,7 @@ export class IgxCalendarComponent extends IgxMonthPickerBaseDirective implements
637650
requestAnimationFrame(() => {
638651
this.monthsView.date = args;
639652
this.focusMonth(event.target);
653+
this.onActiveViewChanged.emit(this.activeView);
640654
});
641655
}
642656

@@ -813,6 +827,7 @@ export class IgxCalendarComponent extends IgxMonthPickerBaseDirective implements
813827

814828
const isPageDown = event.key === 'PageDown';
815829
const step = isPageDown ? 1 : -1;
830+
const previousValue = this.viewDate;
816831
this.viewDate = this.calendarModel.timedelta(this.viewDate, 'year', step);
817832

818833
this.animationAction = isPageDown ? ScrollMonth.NEXT : ScrollMonth.PREV;
@@ -849,6 +864,10 @@ export class IgxCalendarComponent extends IgxMonthPickerBaseDirective implements
849864
if (dayItem && dayItem.isFocusable) { dayItem.nativeElement.focus(); }
850865
};
851866
}
867+
868+
requestAnimationFrame(() => {
869+
this.onViewDateChanged.emit({previousValue, currentValue: this.viewDate});
870+
});
852871
}
853872

854873
/**

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { IgxCalendarBaseDirective } from './calendar-base';
2-
import { HostBinding, Directive, ViewChildren, ElementRef, QueryList } from '@angular/core';
2+
import { HostBinding, Directive, ViewChildren, ElementRef, QueryList, Input } from '@angular/core';
33
import { KEYS } from '../core/utils';
44

55
/**
@@ -36,15 +36,25 @@ export class IgxMonthPickerBaseDirective extends IgxCalendarBaseDirective {
3636
public yearsBtns: QueryList<ElementRef>;
3737

3838

39+
@Input()
3940
/**
4041
* Gets the current active view.
42+
* ```typescript
43+
* this.activeView = calendar.activeView;
44+
* ```
4145
*/
4246
public get activeView(): CalendarView {
4347
return this._activeView;
4448
}
4549

4650
/**
4751
* Sets the current active view.
52+
* ```html
53+
* <igx-calendar [activeView]="1" #calendar></igx-calendar>
54+
* ```
55+
* ```typescript
56+
* calendar.activeView = CalendarView.YEAR;
57+
* ```
4858
*/
4959
public set activeView(val: CalendarView) {
5060
this._activeView = val;
@@ -73,22 +83,28 @@ export class IgxMonthPickerBaseDirective extends IgxCalendarBaseDirective {
7383
* @hidden
7484
*/
7585
public changeYear(event: Date) {
86+
const previousValue = this.viewDate;
7687
this.viewDate = this.calendarModel.getFirstViewDate(event, 'month', this.activeViewIdx);
7788
this.activeView = CalendarView.DEFAULT;
7889

7990
requestAnimationFrame(() => {
8091
if (this.yearsBtns && this.yearsBtns.length) {
8192
this.yearsBtns.find((e: ElementRef, idx: number) => idx === this.activeViewIdx).nativeElement.focus();
8293
}
94+
this.onViewDateChanged.emit({ previousValue, currentValue: this.viewDate });
95+
this.onActiveViewChanged.emit(this.activeView);
8396
});
8497
}
8598

8699
/**
87100
* @hidden
88101
*/
89102
public activeViewDecade(activeViewIdx = 0): void {
90-
this._activeView = CalendarView.DECADE;
103+
this.activeView = CalendarView.DECADE;
91104
this.activeViewIdx = activeViewIdx;
105+
requestAnimationFrame(() => {
106+
this.onActiveViewChanged.emit(this.activeView);
107+
});
92108
}
93109

94110
/**

projects/igniteui-angular/src/lib/calendar/month-picker/month-picker.component.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ describe('IgxMonthPicker', () => {
8989
expect(monthPicker.locale).toEqual('fr');
9090
expect(monthPicker.formatOptions.year).toEqual('2-digit');
9191
expect(monthPicker.value.getDate()).toEqual(today.getDate());
92-
expect(monthPicker.viewDate.getDate()).toEqual(today.getDate());
92+
expect(monthPicker.viewDate.getDate()).toEqual(1);
9393
});
9494

9595
it('should properly set formatOptions and formatViews', () => {
@@ -173,7 +173,7 @@ describe('IgxMonthPicker', () => {
173173
expect(monthPicker.onSelection.emit).toHaveBeenCalled();
174174
expect(currentMonth.nativeElement.textContent.trim()).toEqual('Mar');
175175

176-
const nextDay = new Date(2019, 2, 7);
176+
const nextDay = new Date(2019, 2, 1);
177177
expect(fixture.componentInstance.model.getDate()).toEqual(nextDay.getDate());
178178
});
179179

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export class IgxMonthPickerComponent extends IgxMonthPickerBaseDirective {
121121

122122
requestAnimationFrame(() => {
123123
if (this.dacadeView) { this.dacadeView.el.nativeElement.focus(); }
124+
this.onActiveViewChanged.emit(this.activeView);
124125
});
125126
}
126127

@@ -140,10 +141,15 @@ export class IgxMonthPickerComponent extends IgxMonthPickerBaseDirective {
140141
*/
141142
public nextYear() {
142143
this.yearAction = 'next';
144+
const previousValue = this.viewDate;
143145
this.viewDate = this.calendarModel.getNextYear(this.viewDate);
144146

145147
this.selectDate(this.viewDate);
146148
this.onSelection.emit(this.selectedDates);
149+
150+
requestAnimationFrame(() => {
151+
this.onViewDateChanged.emit({ previousValue, currentValue: this.viewDate });
152+
});
147153
}
148154

149155
/**
@@ -163,10 +169,15 @@ export class IgxMonthPickerComponent extends IgxMonthPickerBaseDirective {
163169
*/
164170
public previousYear() {
165171
this.yearAction = 'prev';
172+
const previousValue = this.viewDate;
166173
this.viewDate = this.calendarModel.getPrevYear(this.viewDate);
167174

168175
this.selectDate(this.viewDate);
169176
this.onSelection.emit(this.selectedDates);
177+
178+
requestAnimationFrame(() => {
179+
this.onViewDateChanged.emit({ previousValue, currentValue: this.viewDate });
180+
});
170181
}
171182

172183
/**
@@ -185,6 +196,7 @@ export class IgxMonthPickerComponent extends IgxMonthPickerBaseDirective {
185196
* @hidden
186197
*/
187198
public selectYear(event: Date) {
199+
const previousValue = this.viewDate;
188200
this.viewDate = new Date(event.getFullYear(), event.getMonth(), event.getDate());
189201
this.activeView = CalendarView.DEFAULT;
190202

@@ -193,6 +205,8 @@ export class IgxMonthPickerComponent extends IgxMonthPickerBaseDirective {
193205

194206
requestAnimationFrame(() => {
195207
if (this.yearsBtn) { this.yearsBtn.nativeElement.focus(); }
208+
this.onViewDateChanged.emit({ previousValue, currentValue: this.viewDate });
209+
this.onActiveViewChanged.emit(this.activeView);
196210
});
197211
}
198212

@@ -207,7 +221,7 @@ export class IgxMonthPickerComponent extends IgxMonthPickerBaseDirective {
207221
/**
208222
* Selects a date.
209223
* ```typescript
210-
* this.monPicker.selectDate(new Date(`2018-06-12`));
224+
* this.monthPicker.selectDate(new Date(`2018-06-12`));
211225
* ```
212226
*/
213227
public selectDate(value: Date) {
@@ -238,7 +252,12 @@ export class IgxMonthPickerComponent extends IgxMonthPickerBaseDirective {
238252
public onKeydownPageUp(event: KeyboardEvent) {
239253
event.preventDefault();
240254
this.yearAction = 'prev';
255+
const previousValue = this.viewDate;
241256
this.viewDate = this.calendarModel.getPrevYear(this.viewDate);
257+
258+
requestAnimationFrame(() => {
259+
this.onViewDateChanged.emit({ previousValue, currentValue: this.viewDate });
260+
});
242261
}
243262

244263
/**
@@ -248,7 +267,12 @@ export class IgxMonthPickerComponent extends IgxMonthPickerBaseDirective {
248267
public onKeydownPageDown(event: KeyboardEvent) {
249268
event.preventDefault();
250269
this.yearAction = 'next';
270+
const previousValue = this.viewDate;
251271
this.viewDate = this.calendarModel.getNextYear(this.viewDate);
272+
273+
requestAnimationFrame(() => {
274+
this.onViewDateChanged.emit({ previousValue, currentValue: this.viewDate });
275+
});
252276
}
253277

254278
/**

0 commit comments

Comments
 (0)