1 import {Component, EventEmitter, Input, Output, ViewChild, OnInit, Optional, Self} from '@angular/core';
2 import {FormatService} from '@eg/core/format.service';
3 import {AbstractControl, ControlValueAccessor, FormControl, FormGroup, NgControl} from '@angular/forms';
4 import {DatetimeValidator} from '@eg/share/validators/datetime_validator.directive';
5 import * as moment from 'moment-timezone';
6 import {DateUtil} from '@eg/share/util/date';
9 selector: 'eg-datetime-select',
10 templateUrl: './datetime-select.component.html',
12 export class DateTimeSelectComponent implements OnInit, ControlValueAccessor {
14 @Input() fieldName: string;
15 @Input() initialIso: string;
16 @Input() required: boolean;
17 @Input() minuteStep = 15; // eslint-disable-line no-magic-numbers
18 @Input() showTZ = true;
19 @Input() timezone: string = this.format.wsOrgTimezone;
20 @Input() readOnly = false;
21 @Input() noPast = false;
22 @Input() noFuture = false;
23 @Input() minDate: any;
24 @Input() maxDate: any;
25 @Output() onChangeAsIso: EventEmitter<string>;
27 dateTimeForm: FormGroup;
29 @ViewChild('datePicker', { static: false }) datePicker;
31 onChange = (_: any) => {};
35 private format: FormatService,
36 private dtv: DatetimeValidator,
39 public controlDir: NgControl, // so that the template can access validation state
41 if (controlDir) { controlDir.valueAccessor = this; }
42 this.onChangeAsIso = new EventEmitter<string>();
43 const startValue = moment.tz([], this.timezone);
44 this.dateTimeForm = new FormGroup({
45 'stringVersion': new FormControl(
46 this.format.transform({value: startValue, datatype: 'timestamp', datePlusTime: true}),
48 'date': new FormControl({
49 year: startValue.year(),
50 month: startValue.month() + 1,
51 day: startValue.date() }),
52 'time': new FormControl({
53 hour: startValue.hour(),
54 minute: startValue.minute(),
61 this.minDate = DateUtil.localYmdPartsFromDate();
64 this.maxDate = DateUtil.localYmdPartsFromDate();
67 this.timezone = this.format.wsOrgTimezone;
69 if (this.initialIso) {
70 this.writeValue(moment(this.initialIso).tz(this.timezone));
72 this.dateTimeForm.get('stringVersion').valueChanges.subscribe((value) => {
73 if ('VALID' === this.dateTimeForm.get('stringVersion').status) {
74 const model = this.format.momentizeDateTimeString(value, this.timezone, false);
75 if (model && model.isValid()) {
77 this.onChangeAsIso.emit(model.toISOString());
78 this.dateTimeForm.patchValue({date: {
80 month: model.month() + 1,
81 day: model.date()}, time: {
83 minute: model.minute(),
85 }, {emitEvent: false, onlySelf: true});
86 this.datePicker.navigateTo({
88 month: model.month() + 1
93 this.dateTimeForm.get('date').valueChanges.subscribe((date) => {
94 const newDate = moment.tz([date.year, (date.month - 1), date.day,
95 this.time.value.hour, this.time.value.minute, 0], this.timezone);
96 this.dateTimeForm.patchValue({stringVersion:
97 this.format.transform({value: newDate, datatype: 'timestamp', datePlusTime: true})},
98 {emitEvent: false, onlySelf: true});
99 this.onChange(newDate);
100 this.onChangeAsIso.emit(newDate.toISOString());
103 this.dateTimeForm.get('time').valueChanges.subscribe((time) => {
104 const newDate = moment.tz([this.date.value.year,
105 (this.date.value.month - 1),
107 time.hour, time.minute, 0],
109 this.dateTimeForm.patchValue({stringVersion:
110 this.format.transform({
111 value: newDate, datatype: 'timestamp', datePlusTime: true})},
112 {emitEvent: false, onlySelf: true});
113 this.onChange(newDate);
114 this.onChangeAsIso.emit(newDate.toISOString());
118 setDatePicker(current: moment.Moment) {
119 const withTZ = current ? current.tz(this.timezone) : moment.tz([], this.timezone);
120 this.dateTimeForm.patchValue({date: {
122 month: withTZ.month() + 1,
123 day: withTZ.date() }});
126 setTimePicker(current: moment.Moment) {
127 const withTZ = current ? current.tz(this.timezone) : moment.tz([], this.timezone);
128 this.dateTimeForm.patchValue({time: {
130 minute: withTZ.minute(),
135 writeValue(value: moment.Moment|string) {
136 if (typeof value === 'string') {
137 if (value.length === 0) {
140 value = this.format.momentizeIsoString(value, this.timezone);
143 if (value !== undefined && value !== null) {
144 this.dateTimeForm.patchValue({
145 stringVersion: this.format.transform({value: value, datatype: 'timestamp', datePlusTime: true})});
146 this.setDatePicker(value);
147 this.setTimePicker(value);
151 registerOnChange(fn: (value: moment.Moment) => any): void {
154 registerOnTouched(fn: () => any): void {
158 firstError(errors: Object) {
159 return Object.values(errors)[0];
162 get stringVersion(): AbstractControl {
163 return this.dateTimeForm.get('stringVersion');
166 get date(): AbstractControl {
167 return this.dateTimeForm.get('date');
170 get time(): AbstractControl {
171 return this.dateTimeForm.get('time');