Skip to content

Commit 1f67247

Browse files
feat(date-range): add onOpened, onClosed, rangeSelected emitters #5732
1 parent 4cf93c0 commit 1f67247

File tree

2 files changed

+77
-45
lines changed

2 files changed

+77
-45
lines changed

Diff for: projects/igniteui-angular/src/lib/date-range/igx-date-range.component.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<div #toggle igxToggle (onOpened)="onOpened()">
1+
<div #toggle igxToggle (onOpened)="onCalendarOpened()">
22
<igx-calendar #calendar (keydown)="onKeyDown($event)" selection="range" [weekStart]="weekStart"
33
[hideOutsideDays]="hideOutsideDays" [monthsViewNumber]="monthsViewNumber"
44
(onSelection)="handleSelection($event)"></igx-calendar>

Diff for: projects/igniteui-angular/src/lib/date-range/igx-date-range.component.ts

+76-44
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, Input, ContentChild, ViewChild, AfterViewInit, AfterContentInit, OnDestroy } from '@angular/core';
1+
import { Component, Input, ContentChild, ViewChild, AfterViewInit, AfterContentInit, OnDestroy, EventEmitter, Output } from '@angular/core';
22
import { InteractionMode } from '../core/enums';
33
import { IgxToggleDirective } from '../directives/toggle/toggle.directive';
44
import { IgxCalendarComponent, WEEKDAYS } from '../calendar/index';
@@ -38,6 +38,15 @@ export class IgxDateRangeComponent implements AfterViewInit, AfterContentInit, O
3838
@Input()
3939
public doneButtonText: string;
4040

41+
@Output()
42+
public rangeSelected: EventEmitter<IgxDateRangeComponent>;
43+
44+
@Output()
45+
public onOpened: EventEmitter<IgxDateRangeComponent>;
46+
47+
@Output()
48+
public onClosed: EventEmitter<IgxDateRangeComponent>;
49+
4150
@ContentChild(IgxDateRangeStartDirective, { read: IgxDateRangeStartDirective, static: false })
4251
public startInput: IgxDateRangeStartDirective;
4352

@@ -64,22 +73,29 @@ export class IgxDateRangeComponent implements AfterViewInit, AfterContentInit, O
6473
private destroy: Subject<boolean>;
6574

6675
constructor() {
67-
this.mode = InteractionMode.Dialog;
68-
this.monthsViewNumber = 1;
69-
this.weekStart = WEEKDAYS.SUNDAY;
7076
this.locale = 'en';
71-
this.todayButtonText = 'Today';
77+
this.monthsViewNumber = 1;
7278
this.doneButtonText = 'Done';
79+
this.todayButtonText = 'Today';
80+
this.weekStart = WEEKDAYS.SUNDAY;
81+
this.mode = InteractionMode.Dialog;
7382
this.destroy = new Subject<boolean>();
83+
this.onOpened = new EventEmitter<IgxDateRangeComponent>();
84+
this.onClosed = new EventEmitter<IgxDateRangeComponent>();
85+
this.rangeSelected = new EventEmitter<IgxDateRangeComponent>();
7486
}
7587

7688
public open() {
7789
this.showCalendar();
7890
}
7991

92+
public close() {
93+
this.hideCalendar();
94+
}
95+
8096
public showToday(event: KeyboardEvent): void {
81-
const today = new Date();
8297
event.stopPropagation();
98+
const today = new Date();
8399
this.calendar.selectDate(today);
84100
this.handleSelection(this.calendar.selectedDates);
85101
}
@@ -107,8 +123,8 @@ export class IgxDateRangeComponent implements AfterViewInit, AfterContentInit, O
107123
})
108124
};
109125
this.dialogOverlaySettings = {
110-
closeOnOutsideClick: true,
111126
modal: true,
127+
closeOnOutsideClick: true,
112128
positionStrategy: new GlobalPositionStrategy()
113129
};
114130
}
@@ -117,29 +133,14 @@ export class IgxDateRangeComponent implements AfterViewInit, AfterContentInit, O
117133
* @hidden
118134
*/
119135
public ngAfterViewInit(): void {
120-
if (this.mode === InteractionMode.DropDown) {
121-
if (this.singleInput) {
122-
fromEvent(this.singleInput.nativeElement, 'keydown').pipe(
123-
takeUntil(this.destroy)
124-
).subscribe((evt: KeyboardEvent) => this.onKeyDown(evt));
125-
126-
this.toggle.onClosed.pipe(
127-
takeUntil(this.destroy)
128-
).subscribe(() => this.singleInput.setFocus());
129-
}
130-
if (this.startInput && this.endInput) {
131-
fromEvent(this.startInput.nativeElement, 'keydown').pipe(
132-
takeUntil(this.destroy)
133-
).subscribe((evt: KeyboardEvent) => this.onKeyDown(evt));
134-
135-
this.toggle.onClosed.pipe(
136-
takeUntil(this.destroy)
137-
).subscribe(() => this.startInput.setFocus());
138-
139-
fromEvent(this.endInput.nativeElement, 'keydown').pipe(
140-
takeUntil(this.destroy)
141-
).subscribe((evt: KeyboardEvent) => this.onKeyDown(evt));
142-
}
136+
switch (this.mode) {
137+
case InteractionMode.DropDown:
138+
this.attachOnKeydown();
139+
this.applyFocusOnClose();
140+
break;
141+
case InteractionMode.Dialog:
142+
this.applyFocusOnClose();
143+
break;
143144
}
144145
}
145146

@@ -159,18 +160,18 @@ export class IgxDateRangeComponent implements AfterViewInit, AfterContentInit, O
159160
case KEYS.UP_ARROW:
160161
case KEYS.UP_ARROW_IE:
161162
if (event.altKey) {
162-
this.hideCalendar(event);
163+
this.hideCalendar();
163164
}
164165
break;
165166
case KEYS.DOWN_ARROW:
166167
case KEYS.DOWN_ARROW_IE:
167168
if (event.altKey) {
168-
this.showDropDown(event);
169+
this.showDropDown();
169170
}
170171
break;
171172
case KEYS.ESCAPE:
172173
case KEYS.ESCAPE_IE:
173-
this.hideCalendar(event);
174+
this.hideCalendar();
174175
break;
175176
}
176177
}
@@ -184,8 +185,9 @@ export class IgxDateRangeComponent implements AfterViewInit, AfterContentInit, O
184185
this.startInput || this.endInput ?
185186
this.handleTwoInputSelection(selectionData) :
186187
this.handleSingleInputSelection(selectionData);
188+
this.rangeSelected.emit(this);
187189
} else {
188-
// first selection in range
190+
// first selection in the range
189191
this.startInput || this.endInput ?
190192
this.handleTwoInputSelection([selectionData[0], null]) :
191193
this.handleSingleInputSelection([selectionData[0], null]);
@@ -195,7 +197,7 @@ export class IgxDateRangeComponent implements AfterViewInit, AfterContentInit, O
195197
/**
196198
* @hidden
197199
*/
198-
public showCalendar(event?: MouseEvent): void {
200+
public showCalendar(event?: MouseEvent | KeyboardEvent): void {
199201
switch (this.mode) {
200202
case InteractionMode.Dialog:
201203
this.showDialog(event);
@@ -207,25 +209,25 @@ export class IgxDateRangeComponent implements AfterViewInit, AfterContentInit, O
207209
// TODO: better error message
208210
throw new Error('Unknown mode.');
209211
}
212+
this.onOpened.emit(this);
210213
}
211214

212215
/**
213216
* @hidden
214217
*/
215-
public hideCalendar(event: MouseEvent | KeyboardEvent) {
216-
event.stopPropagation();
217-
event.preventDefault();
218+
public hideCalendar(): void {
218219
if (!this.toggle.collapsed) {
219-
const element = event.target as HTMLElement;
220220
this.toggle.close();
221-
element.focus();
221+
this.startInput ? this.startInput.nativeElement.focus() :
222+
this.singleInput.nativeElement.focus();
222223
}
224+
this.onClosed.emit(this);
223225
}
224226

225227
/**
226228
* @hidden
227229
*/
228-
public onOpened(): void {
230+
public onCalendarOpened(): void {
229231
requestAnimationFrame(() => {
230232
this.calendar.daysView.focusActiveDate();
231233
});
@@ -253,13 +255,13 @@ export class IgxDateRangeComponent implements AfterViewInit, AfterContentInit, O
253255
this.activateToggleOpen(this.dropDownOverlaySettings);
254256
}
255257

256-
private handleSingleInputSelection(selectionData: Date[]) {
258+
private handleSingleInputSelection(selectionData: Date[]): void {
257259
if (this.singleInput) {
258260
this.singleInput.value = this.extractRange(selectionData);
259261
}
260262
}
261263

262-
private handleTwoInputSelection(selectionData: Date[]) {
264+
private handleTwoInputSelection(selectionData: Date[]): void {
263265
const selectionRange = this.extractRange(selectionData);
264266
if (this.startInput) {
265267
this.startInput.value = selectionRange[0];
@@ -308,9 +310,39 @@ export class IgxDateRangeComponent implements AfterViewInit, AfterContentInit, O
308310
}
309311

310312
private validateNgContent(): void {
311-
if (this.startInput && !this.endInput || !this.startInput && this.endInput) {
313+
if (!this.singleInput && (!this.startInput || !this.endInput)) {
312314
// TODO: better error message
313315
throw new Error('You must apply both igxDateRangeStart and igxDateRangeEnd if you are using two input elements.');
314316
}
315317
}
318+
319+
private attachOnKeydown(): void {
320+
if (this.singleInput) {
321+
fromEvent(this.singleInput.nativeElement, 'keydown').pipe(
322+
takeUntil(this.destroy)
323+
).subscribe((evt: KeyboardEvent) => this.onKeyDown(evt));
324+
}
325+
if (this.startInput && this.endInput) {
326+
fromEvent(this.startInput.nativeElement, 'keydown').pipe(
327+
takeUntil(this.destroy)
328+
).subscribe((evt: KeyboardEvent) => this.onKeyDown(evt));
329+
330+
fromEvent(this.endInput.nativeElement, 'keydown').pipe(
331+
takeUntil(this.destroy)
332+
).subscribe((evt: KeyboardEvent) => this.onKeyDown(evt));
333+
}
334+
}
335+
336+
private applyFocusOnClose() {
337+
if (this.singleInput) {
338+
this.toggle.onClosed.pipe(
339+
takeUntil(this.destroy)
340+
).subscribe(() => this.singleInput.setFocus());
341+
}
342+
if (this.startInput) {
343+
this.toggle.onClosed.pipe(
344+
takeUntil(this.destroy)
345+
).subscribe(() => this.startInput.setFocus());
346+
}
347+
}
316348
}

0 commit comments

Comments
 (0)