1 /* eslint-disable eqeqeq */
2 import {Component, OnInit, Input, Output, EventEmitter, forwardRef} from '@angular/core';
3 import {NgbDateStruct} from '@ng-bootstrap/ng-bootstrap';
4 import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
5 import {DateUtil} from '@eg/share/util/date';
8 * RE: displaying locale dates in the input field:
9 * https://github.com/ng-bootstrap/ng-bootstrap/issues/754
10 * https://stackoverflow.com/questions/40664523/angular2-ngbdatepicker-how-to-format-date-in-inputfield
14 selector: 'eg-date-select',
15 templateUrl: './date-select.component.html',
16 styleUrls: ['date-select.component.css'],
18 provide: NG_VALUE_ACCESSOR,
19 useExisting: forwardRef(() => DateSelectComponent),
23 export class DateSelectComponent implements OnInit, ControlValueAccessor {
25 @Input() initialIso: string; // ISO string
26 @Input() initialYmd: string; // YYYY-MM-DD (uses local time zone)
27 @Input() initialDate: Date; // Date object
28 @Input() required: boolean;
29 @Input() fieldName: string;
31 @Input() disabled: boolean;
32 @Input() readOnly: boolean;
34 // Sometimes it's helpful to allow the date selector to expand
35 // to fill its container for visual consistency with other inputs.
36 @Input() noMaxWidth = false;
38 current: NgbDateStruct;
40 @Output() onChangeAsDate: EventEmitter<Date>;
41 @Output() onChangeAsIso: EventEmitter<string>;
42 @Output() onChangeAsYmd: EventEmitter<string>;
43 @Output() onCleared: EventEmitter<string>;
45 // convenience methods to access current selected date
46 currentAsYmd(): string {
47 if (this.current == null) { return null; }
48 if (!this.isValidDate(this.current)) { return null; }
49 return `${this.current.year}-${String(this.current.month).padStart(2, '0')}-${String(this.current.day).padStart(2, '0')}`;
51 currentAsIso(): string {
52 if (this.current == null) { return null; }
53 if (!this.isValidDate(this.current)) { return null; }
54 const ymd = `${this.current.year}-${String(this.current.month).padStart(2, '0')}-${String(this.current.day).padStart(2, '0')}`;
55 const date = DateUtil.localDateFromYmd(ymd);
56 const iso = date.toISOString();
59 currentAsDate(): Date {
60 if (this.current == null) { return null; }
61 if (!this.isValidDate(this.current)) { return null; }
62 const ymd = `${this.current.year}-${String(this.current.month).padStart(2, '0')}-${String(this.current.day).padStart(2, '0')}`;
63 const date = DateUtil.localDateFromYmd(ymd);
67 // Stub functions required by ControlValueAccessor
68 propagateChange = (_: any) => {};
69 propagateTouch = () => {};
72 this.onChangeAsDate = new EventEmitter<Date>();
73 this.onChangeAsIso = new EventEmitter<string>();
74 this.onChangeAsYmd = new EventEmitter<string>();
75 this.onCleared = new EventEmitter<string>();
80 if (this.initialYmd) {
81 this.initialDate = DateUtil.localDateFromYmd(this.initialYmd);
83 } else if (this.initialIso) {
84 this.initialDate = new Date(this.initialIso);
87 if (this.initialDate) {
88 this.writeValue(this.initialDate);
92 isValidDate(dt: NgbDateStruct): dt is NgbDateStruct {
93 if (!dt) { return false; }
94 return (<NgbDateStruct>dt).year !== undefined;
98 if (this.current === null) {
99 this.onCleared.emit('cleared');
100 } else if (this.isValidDate(this.current)) {
101 this.onDateSelect(this.current);
103 // ignoring invalid input for now
107 const ymd = `${evt.year}-${String(evt.month).padStart(2, '0')}-${String(evt.day).padStart(2, '0')}`;
108 const date = DateUtil.localDateFromYmd(ymd);
109 const iso = date.toISOString();
110 this.onChangeAsDate.emit(date);
111 this.onChangeAsYmd.emit(ymd);
112 this.onChangeAsIso.emit(iso);
113 this.propagateChange(date);
116 // onDateSelect() is not called when the value is cleared.
118 inputChanged(value) {
119 if (value === null) {
120 this.onChangeAsDate.emit(null);
121 this.onChangeAsYmd.emit(null);
122 this.onChangeAsIso.emit(null);
123 this.propagateChange(null);
135 writeValue(value: Date) {
138 year: value.getFullYear(),
139 month: value.getMonth() + 1,
143 // Allow the value to be cleared via model change.
148 registerOnChange(fn) {
149 this.propagateChange = fn;
152 registerOnTouched(fn) {
153 this.propagateTouch = fn;