projects/rebirth-ng/src/lib/date-picker/date-picker-popup.component.ts
exportAs | datePickerPopup |
providers |
{
: , : (() => ), : true
}
|
selector | re-date-picker-popup |
styleUrls | date-picker-popup.component.scss |
templateUrl | ./date-picker-popup.component.html |
Properties |
|
Methods |
|
Inputs |
Outputs |
HostListeners |
constructor(elementRef: ElementRef, renderer: Renderer2, rebirthNGConfig: RebirthNGConfig, changeDetectorRef: ChangeDetectorRef)
|
|||||||||||||||
Parameters :
|
cssClass
|
Type: |
dateConverter
|
Type: |
dateFormat
|
Type: |
disabled
|
Default value: |
locale
|
Type: |
maxDate
|
|
minDate
|
|
showTimePicker
|
Type: |
selectedDateChange
|
$event type: EventEmitter
|
click |
Arguments : '$event'
|
click($event: Event)
|
Private fillLeft | ||||||
fillLeft(num: number)
|
||||||
Parameters :
Returns :
string
|
Private fillRange | ||||||
fillRange(number: number)
|
||||||
Parameters :
Returns :
any
|
hasNextMonth |
hasNextMonth()
|
Returns :
boolean
|
hasPreMonth |
hasPreMonth()
|
Returns :
boolean
|
isDisabledDay | ||||
isDisabledDay(date: )
|
||||
Parameters :
Returns :
boolean
|
isSelectDay | ||||
isSelectDay(date: )
|
||||
Parameters :
Returns :
boolean
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
onDisplayWeeksChange |
onDisplayWeeksChange()
|
Returns :
void
|
onNextMonth |
onNextMonth()
|
Returns :
void
|
onPreMonth |
onPreMonth()
|
Returns :
void
|
onSelectDate | ||||||
onSelectDate($event: , date: )
|
||||||
Parameters :
Returns :
void
|
Private onSelectDateChanged |
onSelectDateChanged()
|
Returns :
void
|
onTimeChange |
onTimeChange()
|
Returns :
void
|
onYearRangeChange |
onYearRangeChange()
|
Returns :
void
|
registerOnChange | ||||||
registerOnChange(fn: any)
|
||||||
Parameters :
Returns :
void
|
registerOnTouched | ||||||
registerOnTouched(fn: any)
|
||||||
Parameters :
Returns :
void
|
Optional setDisabledState | ||||||
setDisabledState(isDisabled: boolean)
|
||||||
Parameters :
Returns :
void
|
today | ||||
today($event: )
|
||||
Parameters :
Returns :
void
|
todayIsOutOfRange |
todayIsOutOfRange()
|
Returns :
boolean
|
writeValue | ||||||
writeValue(obj: any)
|
||||||
Parameters :
Returns :
void
|
Private _maxDate |
_maxDate:
|
Type : Date
|
Private _minDate |
_minDate:
|
Type : Date
|
currentHour |
currentHour:
|
Type : number
|
currentMinute |
currentMinute:
|
Type : number
|
currentMonth |
currentMonth:
|
Type : number
|
currentSecond |
currentSecond:
|
Type : number
|
currentYear |
currentYear:
|
Type : number
|
dateConfig |
dateConfig:
|
Type : any
|
Static DAY_DURATION |
DAY_DURATION:
|
Default value : 24 * 60 * 60 * 1000
|
displayWeeks |
displayWeeks:
|
Type : any[]
|
hourOptions |
hourOptions:
|
Type : string[]
|
minuteOptions |
minuteOptions:
|
Type : string[]
|
Private onChange |
onChange:
|
Default value : (_: any) => null
|
Private onTouched |
onTouched:
|
Default value : () => null
|
secondOptions |
secondOptions:
|
Type : string[]
|
selectedDate |
selectedDate:
|
Type : Date
|
yearOptions |
yearOptions:
|
Type : number[]
|
maxDate | ||||
getmaxDate()
|
||||
setmaxDate(date: )
|
||||
Parameters :
Returns :
void
|
minDate | ||||
getminDate()
|
||||
setminDate(date: )
|
||||
Parameters :
Returns :
void
|
import {
Component,
OnInit,
Input,
HostListener,
forwardRef,
ElementRef,
Renderer2,
Output,
EventEmitter,
ChangeDetectorRef
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { SelectDateChangeEventArgs, SelectDateChangeReason } from './date-change-event-args.model';
import { RebirthNGConfig } from '../rebirth-ng.config';
import { DateConverter } from '../utils/date-converter';
import { DefaultDateConverter } from '../utils/default-date-converter';
import { isValidDate } from '../utils/date-utils';
import { stopPropagationIfExist } from '../utils/dom-utils';
@Component({
selector: 're-date-picker-popup',
templateUrl: './date-picker-popup.component.html',
styleUrls: ['./date-picker-popup.component.scss'],
exportAs: 'datePickerPopup',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DatePickerPopupComponent),
multi: true
}]
})
export class DatePickerPopupComponent implements OnInit, ControlValueAccessor {
static DAY_DURATION = 24 * 60 * 60 * 1000;
private _maxDate: Date;
private _minDate: Date;
selectedDate: Date;
@Input() showTimePicker: boolean;
@Input() cssClass: string;
@Input() dateConverter: DateConverter;
@Input() locale: string;
@Output() selectedDateChange = new EventEmitter<SelectDateChangeEventArgs>();
@Input() dateFormat: string;
@Input() disabled = false;
currentYear: number;
currentMonth: number;
currentHour: number;
currentMinute: number;
currentSecond: number;
dateConfig: any;
hourOptions: string[];
minuteOptions: string[];
secondOptions: string[];
displayWeeks: any[];
yearOptions: number[];
private onChange = (_: any) => null;
private onTouched = () => null;
constructor(private elementRef: ElementRef,
private renderer: Renderer2,
private rebirthNGConfig: RebirthNGConfig,
private changeDetectorRef: ChangeDetectorRef) {
this.locale = this.rebirthNGConfig.datePicker.locale;
this.dateConverter = rebirthNGConfig.datePicker.dateConverter || new DefaultDateConverter();
this.dateConfig = rebirthNGConfig.datePicker;
this.showTimePicker = rebirthNGConfig.datePicker.timePicker;
this._minDate = new Date(this.dateConfig.min, 0, 1, 0, 0, 0);
this._maxDate = new Date(this.dateConfig.max, 11, 31, 23, 59, 59);
this.renderer.setStyle(this.elementRef.nativeElement, 'display', 'inline-block');
}
@Input() set maxDate(date: Date | any) {
const parseDate = this.dateConverter.parse(date, this.dateFormat, this.locale);
if (parseDate) {
this._maxDate = parseDate;
this.onYearRangeChange();
}
}
get maxDate() {
return this._maxDate;
}
@Input() set minDate(date: Date | any) {
const parseDate = this.dateConverter.parse(date, this.dateFormat, this.locale);
if (parseDate) {
this._minDate = parseDate;
this.onYearRangeChange();
}
}
get minDate() {
return this._minDate;
}
ngOnInit() {
this.hourOptions = this.fillRange(24);
this.minuteOptions = this.fillRange(60);
this.secondOptions = this.fillRange(60);
this.onSelectDateChanged();
this.onDisplayWeeksChange();
this.onYearRangeChange();
}
private fillRange(number: number) {
return new Array(number).fill(0).map((value, index) => this.fillLeft(index));
}
writeValue(obj: any): void {
this.selectedDate = obj ? this.dateConverter.parse(obj, this.dateFormat, this.locale) : null;
this.onSelectDateChanged();
this.onDisplayWeeksChange();
this.changeDetectorRef.markForCheck();
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.disabled = isDisabled;
}
todayIsOutOfRange() {
return this.isDisabledDay(new Date());
}
today($event) {
this.onSelectDate($event, new Date());
}
onSelectDate($event, date) {
stopPropagationIfExist($event);
if (this.isDisabledDay(date)) {
return;
}
const selectedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
this.currentHour, this.currentMinute, this.currentSecond);
this.onTouched();
this.writeValue(selectedDate);
this.onChange(selectedDate);
this.selectedDateChange.emit({ reason: SelectDateChangeReason.date, date: this.selectedDate });
if (this.currentMonth !== this.selectedDate.getMonth() || this.currentYear !== this.selectedDate.getFullYear()) {
this.currentYear = this.selectedDate.getFullYear();
this.currentMonth = this.selectedDate.getMonth();
this.onDisplayWeeksChange();
}
}
onTimeChange() {
const date = this.selectedDate || new Date();
this.selectedDate = new Date(date.getFullYear(), date.getMonth(),
date.getDate(), this.currentHour, this.currentMinute, this.currentSecond);
this.onTouched();
this.writeValue(this.selectedDate);
this.onChange(this.selectedDate);
this.selectedDateChange.emit({ reason: SelectDateChangeReason.time, date: this.selectedDate });
}
hasPreMonth() {
return this.currentMonth > 0 || this.currentYear > this.minDate.getFullYear();
}
onPreMonth() {
if (!this.hasPreMonth()) {
return;
}
if (this.currentMonth > 0) {
this.currentMonth -= 1;
} else {
this.currentMonth = 11;
this.currentYear -= 1;
}
this.onDisplayWeeksChange();
}
hasNextMonth() {
return this.currentMonth < 11 || this.currentYear < this.maxDate.getFullYear();
}
onNextMonth() {
if (!this.hasNextMonth()) {
return;
}
if (this.currentMonth < 11) {
this.currentMonth += 1;
} else {
this.currentMonth = 0;
this.currentYear += 1;
}
this.onDisplayWeeksChange();
}
isDisabledDay(date) {
const minDate = new Date(this.minDate.getFullYear(), this.minDate.getMonth(), this.minDate.getDate(), 0, 0, 0);
const maxDate = new Date(this.maxDate.getFullYear(), this.maxDate.getMonth(), this.maxDate.getDate(), 23, 59, 59);
return this.disabled || (date.getTime() < minDate.getTime() ||
date.getTime() > maxDate.getTime());
}
isSelectDay(date) {
if (!this.selectedDate || !date) {
return false;
}
return date.getFullYear() === this.selectedDate.getFullYear() &&
date.getMonth() === this.selectedDate.getMonth() &&
date.getDate() === this.selectedDate.getDate();
}
onYearRangeChange() {
if (!isValidDate(this.minDate) || !isValidDate(this.maxDate)) {
return;
}
const minYear = this.minDate.getFullYear();
const maxYear = this.maxDate.getFullYear();
this.yearOptions = new Array(maxYear - minYear + 1).fill(0).map((value, index) => {
return minYear + index;
});
}
@HostListener('click', ['$event'])
onHostClick($event: Event) {
stopPropagationIfExist($event);
}
private onSelectDateChanged() {
let date = this.selectedDate || new Date();
if (date.getTime() < this.minDate.getTime()) {
date = this.minDate;
}
if (date.getTime() > this.maxDate.getTime()) {
date = this.maxDate;
}
this.currentYear = date.getFullYear();
this.currentMonth = date.getMonth();
this.currentHour = this.showTimePicker ? date.getHours() : 0;
this.currentMinute = this.showTimePicker ? date.getMinutes() : 0;
this.currentSecond = this.showTimePicker ? date.getSeconds() : 0;
}
private fillLeft(num: number) {
return num < 10 ? `0${num}` : `${num}`;
}
onDisplayWeeksChange() {
const firstDayOfMonth = new Date(this.currentYear, this.currentMonth, 1);
const weekOfDay = firstDayOfMonth.getDay();
const startDate = new Date(firstDayOfMonth.getTime() - weekOfDay * DatePickerPopupComponent.DAY_DURATION);
const displayWeeks = [];
for (let i = 0; i < 6; i++) {
const startWeekDate = startDate.getTime() + i * 7 * DatePickerPopupComponent.DAY_DURATION;
const weekDays = new Array(7).fill(0).map((value, index) => {
const currentDate = new Date(startWeekDate + index * DatePickerPopupComponent.DAY_DURATION);
return {
day: this.fillLeft(currentDate.getDate()),
date: currentDate,
inMonth: currentDate.getMonth().toString() === this.currentMonth.toString()
};
});
displayWeeks.push(weekDays);
}
this.displayWeeks = displayWeeks;
}
}
<div class="month-view {{cssClass}}">
<table class="table month-view-table">
<thead>
<tr>
<td>
<a *ngIf="hasPreMonth()" class="btn-link glyphicon glyphicon-chevron-left pull-right" aria-hidden="true"
(click)="onPreMonth()"></a>
</td>
<td colspan="5" class="text-center">
<select class="date-select" [(ngModel)]="currentMonth" (change)="onDisplayWeeksChange()">
<option *ngFor="let item of dateConfig.months; let $index = index" [ngValue]="$index">{{item}}</option>
</select>
<select class="date-select" [(ngModel)]="currentYear" (change)="onDisplayWeeksChange()">
<option *ngFor="let item of yearOptions" [ngValue]="item">{{item}}</option>
</select>
</td>
<td>
<a *ngIf="hasNextMonth()" class="btn-link glyphicon glyphicon-chevron-right pull-right" aria-hidden="true"
(click)="onNextMonth()"></a>
</td>
</tr>
<tr class="small text-center week-header bg-info">
<td *ngFor="let item of dateConfig.weeks">{{item}}</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let week of displayWeeks">
<td *ngFor="let day of week" class="day"
[ngClass]="{'out-of-month': !day.inMonth, 'in-month-day': day.inMonth,'disabled': isDisabledDay(day.date)}"
(click)="onSelectDate($event, day.date)">
<div class="calendar-date" [ngClass]="{'bg-primary': isSelectDay(day.date)}">{{day.day}}</div>
</td>
</tr>
</tbody>
<tfoot>
<tr class="time-picker-view bg-info">
<td colspan="7">
<div *ngIf="showTimePicker" class="pull-left time-panel">
<select class="date-select" [(ngModel)]="currentHour" name="hours" [disabled]="disabled"
(change)="onTimeChange()">
<option *ngFor="let item of hourOptions; let $index = index" [ngValue]="$index">{{item}}</option>
</select>
:
<select class="date-select" [(ngModel)]="currentMinute" name="minutes" [disabled]="disabled"
(change)="onTimeChange()">
<option *ngFor="let item of minuteOptions; let $index = index" [ngValue]="$index">{{item}}</option>
</select>
:
<select class="date-select" [(ngModel)]="currentSecond" name="seconds" [disabled]="disabled"
(change)="onTimeChange()">
<option *ngFor="let item of secondOptions; let $index = index" [ngValue]="$index">{{item}}</option>
</select>
</div>
<button type="button" class="btn btn-sm btn-primary pull-right" [disabled]="todayIsOutOfRange()" (click)="today($event)">
{{dateConfig.today}}
</button>
</td>
</tr>
</tfoot>
</table>
</div>