projects/rebirth-ng/src/lib/date-picker/date-picker.directive.ts
OnInit
ControlValueAccessor
OnDestroy
providers |
{
: , : (() => ), : true
}
|
selector | [reDatePicker] |
Properties |
|
Methods |
|
Inputs |
HostListeners |
constructor(elementRef: ElementRef, viewContainerRef: ViewContainerRef, componentFactoryResolver: ComponentFactoryResolver, renderer: Renderer2, injector: Injector, positionService: PositionService, rebirthNGConfig: RebirthNGConfig)
|
||||||||||||||||||||||||
Parameters :
|
appendBody
|
Default value: |
cssClass
|
Type: |
dateConverter
|
Type: |
dateFormat
|
Type: |
disabled
|
Default value: |
locale
|
Type: |
maxDate
|
|
minDate
|
|
placement
|
Type:
Default value: |
selectedDate
|
Type: |
showTimePicker
|
Type: |
blur |
Arguments : '$event'
|
blur()
|
change |
Arguments : '$event'
|
change($event: )
|
document:click |
Arguments : '$event'
|
document:click($event: Event)
|
keyup.esc |
Arguments : '$event'
|
keyup.esc()
|
Private applyPopupStyling | ||||||
applyPopupStyling(nativeElement: any)
|
||||||
Parameters :
Returns :
void
|
Private fillPopupData |
fillPopupData()
|
Returns :
void
|
Private getDateFormat |
getDateFormat()
|
Returns :
any
|
hide |
hide()
|
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
registerOnChange | ||||||
registerOnChange(fn: any)
|
||||||
Parameters :
Returns :
void
|
registerOnTouched | ||||||
registerOnTouched(fn: any)
|
||||||
Parameters :
Returns :
void
|
Private removePopView |
removePopView()
|
Returns :
void
|
setDisabledState | ||||||
setDisabledState(isDisabled: boolean)
|
||||||
Parameters :
Returns :
void
|
show |
show()
|
Returns :
void
|
toggle | ||||||
toggle($event: Event)
|
||||||
Parameters :
Returns :
void
|
Private writeModelValue | ||||||
writeModelValue(selectDate: Date)
|
||||||
Parameters :
Returns :
void
|
writeValue | ||||||
writeValue(obj: any)
|
||||||
Parameters :
Returns :
void
|
Private _dateFormat |
_dateFormat:
|
Type : string
|
Private _maxDate |
_maxDate:
|
Type : Date
|
Private _minDate |
_minDate:
|
Type : Date
|
Private cmpRef |
cmpRef:
|
Type : ComponentRef<DatePickerPopupComponent>
|
dateConfig |
dateConfig:
|
Type : any
|
isOpen |
isOpen:
|
Default value : false
|
Private lastEventTarget |
lastEventTarget:
|
Type : any
|
Private onChange |
onChange:
|
Default value : (_: any) => null
|
Private onTouched |
onTouched:
|
Default value : () => null
|
maxDate | ||||
getmaxDate()
|
||||
setmaxDate(date: )
|
||||
Parameters :
Returns :
void
|
minDate | ||||
getminDate()
|
||||
setminDate(date: )
|
||||
Parameters :
Returns :
void
|
dateFormat | ||||||
getdateFormat()
|
||||||
setdateFormat(dateFormat: string)
|
||||||
Parameters :
Returns :
void
|
import {
ComponentFactoryResolver, ComponentRef, Directive, ElementRef, forwardRef, HostListener, Injector, Input, OnInit,
Renderer2,
ViewContainerRef, OnDestroy
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { PositionService } from '../position/positioning.service';
import { DatePickerPopupComponent } from './date-picker-popup.component';
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';
@Directive({
selector: '[reDatePicker]',
exportAs: 'datePicker',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DatePickerDirective),
multi: true
}]
})
export class DatePickerDirective implements OnInit, ControlValueAccessor, OnDestroy {
@Input() placement: 'top' | 'top-left' | 'top-right' | 'bottom' | 'bottom-left' | 'bottom-right' = 'bottom-left';
@Input() selectedDate: Date;
@Input() locale: string;
@Input() showTimePicker: boolean;
@Input() cssClass: string;
@Input() disabled = false;
@Input() dateConverter: DateConverter;
@Input() appendBody = false;
isOpen = false;
dateConfig: any;
private _dateFormat: string;
private _maxDate: Date;
private _minDate: Date;
private lastEventTarget: any;
private cmpRef: ComponentRef<DatePickerPopupComponent>;
private onChange = (_: any) => null;
private onTouched = () => null;
constructor(private elementRef: ElementRef, private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver, private renderer: Renderer2,
private injector: Injector, private positionService: PositionService,
private rebirthNGConfig: RebirthNGConfig) {
this.dateConfig = rebirthNGConfig.datePicker;
this.dateConverter = rebirthNGConfig.datePicker.dateConverter || new DefaultDateConverter();
this.showTimePicker = rebirthNGConfig.datePicker.timePicker;
this.locale = rebirthNGConfig.datePicker.locale;
this._minDate = new Date(this.dateConfig.min, 0, 1, 0, 0, 0);
this._maxDate = new Date(this.dateConfig.max, 11, 31, 23, 59, 59);
}
@Input()
set maxDate(date: Date | any) {
const parseDate = this.dateConverter.parse(date, this.getDateFormat(), this.locale);
if (parseDate) {
this._maxDate = parseDate;
}
}
get maxDate() {
return this._maxDate;
}
@Input()
set minDate(date: Date | any) {
const parseDate = this.dateConverter.parse(date, this.getDateFormat(), this.locale);
if (parseDate) {
this._minDate = parseDate;
}
}
get minDate() {
return this._minDate;
}
@Input()
set dateFormat(dateFormat: string) {
if (dateFormat && this._dateFormat !== dateFormat) {
this._dateFormat = dateFormat;
this.writeModelValue(this.selectedDate);
}
}
get dateFormat() {
return this._dateFormat;
}
ngOnInit() {
const factory = this.componentFactoryResolver.resolveComponentFactory(DatePickerPopupComponent);
const viewContainerRef = this.appendBody ? this.rebirthNGConfig.rootContainer : this.viewContainerRef;
// EXCEPTION: Expression has changed after it was checked when append to body;
setTimeout(() => {
this.cmpRef = <ComponentRef<DatePickerPopupComponent>>viewContainerRef
.createComponent(factory, viewContainerRef.length, this.injector);
this.applyPopupStyling(this.cmpRef.location.nativeElement);
const component = this.cmpRef.instance;
this.hide();
component.writeValue(this.selectedDate);
this.fillPopupData();
component.ngOnInit();
component.registerOnChange((selectedDate) => {
this.writeValue(selectedDate);
this.onChange(selectedDate);
});
component.selectedDateChange.subscribe((arg: SelectDateChangeEventArgs) => {
if (arg.reason === SelectDateChangeReason.date) {
this.hide();
}
});
}, 0);
}
writeValue(obj: any): void {
this.selectedDate = obj ? this.dateConverter.parse(obj, this.getDateFormat(), this.locale) : null;
this.writeModelValue(this.selectedDate);
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
this.renderer.setProperty(this.elementRef.nativeElement, 'disabled', isDisabled);
if (this.isOpen) {
this.cmpRef.instance.setDisabledState(isDisabled);
}
}
toggle($event: Event) {
this.lastEventTarget = $event.target;
if (this.isOpen) {
this.hide();
return;
}
this.show();
}
@HostListener('document:click', ['$event'])
onDocumentClick($event: Event) {
const hostElement = this.elementRef.nativeElement;
if ([hostElement, this.lastEventTarget].indexOf($event.target) === -1) {
this.hide();
}
}
show() {
const component = this.cmpRef.instance;
component.writeValue(this.selectedDate);
this.fillPopupData();
this.isOpen = true;
const targetElement = this.cmpRef.location.nativeElement;
const hostElement = this.elementRef.nativeElement;
this.renderer.setStyle(targetElement, 'display', 'inline-block');
const clientRect = this.positionService.positionElements(hostElement, targetElement, this.placement, this.appendBody);
this.renderer.setStyle(targetElement, 'left', `${clientRect.left}px`);
this.renderer.setStyle(targetElement, 'top', `${clientRect.top}px`);
}
hide() {
if (this.cmpRef) {
this.isOpen = false;
const target = this.cmpRef.location.nativeElement;
this.renderer.setStyle(target, 'display', 'none');
}
}
@HostListener('blur', ['$event'])
onBlur() {
this.onTouched();
}
@HostListener('change', ['$event'])
onChangeFromInput($event) {
const value = $event.target.value;
let parseDate = value ? this.dateConverter.parse(value, this.dateFormat, this.locale) : null;
if (parseDate) {
if (parseDate.getTime() < this.minDate.getTime()) {
parseDate = this.minDate;
}
if (parseDate.getTime() > this.maxDate.getTime()) {
parseDate = this.maxDate;
}
}
this.writeValue(parseDate);
this.onChange(this.selectedDate);
}
@HostListener('keyup.esc', ['$event'])
onEscKeyup() {
this.hide();
}
ngOnDestroy(): void {
this.removePopView();
}
private removePopView() {
if (this.cmpRef) {
this.cmpRef.destroy();
}
}
private writeModelValue(selectDate: Date) {
const value = selectDate ? this.dateConverter.format(selectDate, this.getDateFormat(), this.locale) : '';
this.renderer.setProperty(this.elementRef.nativeElement, 'value', value);
if (this.isOpen) {
this.cmpRef.instance.writeValue(selectDate);
this.onTouched();
}
}
private getDateFormat() {
if (this.dateFormat) {
return this.dateFormat;
}
return this.showTimePicker ? this.dateConfig.format.time : this.dateConfig.format.date;
}
private applyPopupStyling(nativeElement: any) {
this.renderer.addClass(nativeElement, 'dropdown-menu');
this.renderer.setStyle(nativeElement, 'padding', '0px');
}
private fillPopupData() {
['showTimePicker', 'maxDate', 'minDate', 'cssClass', 'disabled', 'dateConverter', 'locale', 'dateFormat']
.forEach(key => {
if (this[key] !== undefined) {
this.cmpRef.instance[key] = this[key];
}
});
}
}