1 import {Component, OnInit, Input, Output, ViewChild, EventEmitter, forwardRef} from '@angular/core';
2 import {NgbDateStruct} from '@ng-bootstrap/ng-bootstrap';
3 import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
6 * RE: displaying locale dates in the input field:
7 * https://github.com/ng-bootstrap/ng-bootstrap/issues/754
8 * https://stackoverflow.com/questions/40664523/angular2-ngbdatepicker-how-to-format-date-in-inputfield
12 selector: 'eg-date-select',
13 templateUrl: './date-select.component.html',
14 styleUrls: ['date-select.component.css'],
16 provide: NG_VALUE_ACCESSOR,
17 useExisting: forwardRef(() => DateSelectComponent),
21 export class DateSelectComponent implements OnInit, ControlValueAccessor {
23 @Input() initialIso: string; // ISO string
24 @Input() initialYmd: string; // YYYY-MM-DD (uses local time zone)
25 @Input() initialDate: Date; // Date object
26 @Input() required: boolean;
27 @Input() fieldName: string;
29 @Input() disabled: boolean;
30 @Input() readOnly: boolean;
32 current: NgbDateStruct;
34 @Output() onChangeAsDate: EventEmitter<Date>;
35 @Output() onChangeAsIso: EventEmitter<string>;
36 @Output() onChangeAsYmd: EventEmitter<string>;
37 @Output() onCleared: EventEmitter<string>;
39 // convenience methods to access current selected date
40 currentAsYmd(): string {
41 if (this.current == null) { return null; }
42 if (!this.isValidDate(this.current)) { return null; }
43 return `${this.current.year}-${String(this.current.month).padStart(2, '0')}-${String(this.current.day).padStart(2, '0')}`;
45 currentAsIso(): string {
46 if (this.current == null) { return null; }
47 if (!this.isValidDate(this.current)) { return null; }
48 const ymd = `${this.current.year}-${String(this.current.month).padStart(2, '0')}-${String(this.current.day).padStart(2, '0')}`;
49 const date = this.localDateFromYmd(ymd);
50 const iso = date.toISOString();
53 currentAsDate(): Date {
54 if (this.current == null) { return null; }
55 if (!this.isValidDate(this.current)) { return null; }
56 const ymd = `${this.current.year}-${String(this.current.month).padStart(2, '0')}-${String(this.current.day).padStart(2, '0')}`;
57 const date = this.localDateFromYmd(ymd);
61 // Stub functions required by ControlValueAccessor
62 propagateChange = (_: any) => {};
63 propagateTouch = () => {};
66 this.onChangeAsDate = new EventEmitter<Date>();
67 this.onChangeAsIso = new EventEmitter<string>();
68 this.onChangeAsYmd = new EventEmitter<string>();
69 this.onCleared = new EventEmitter<string>();
74 if (this.initialYmd) {
75 this.initialDate = this.localDateFromYmd(this.initialYmd);
77 } else if (this.initialIso) {
78 this.initialDate = new Date(this.initialIso);
81 if (this.initialDate) {
82 this.writeValue(this.initialDate);
86 isValidDate(dt: NgbDateStruct): dt is NgbDateStruct {
87 if (!dt) { return false; }
88 return (<NgbDateStruct>dt).year !== undefined;
92 if (this.current === null) {
93 this.onCleared.emit('cleared');
94 } else if (this.isValidDate(this.current)) {
95 this.onDateSelect(this.current);
97 // ignoring invalid input for now
101 const ymd = `${evt.year}-${String(evt.month).padStart(2, '0')}-${String(evt.day).padStart(2, '0')}`;
102 const date = this.localDateFromYmd(ymd);
103 const iso = date.toISOString();
104 this.onChangeAsDate.emit(date);
105 this.onChangeAsYmd.emit(ymd);
106 this.onChangeAsIso.emit(iso);
107 this.propagateChange(date);
110 // Create a date in the local time zone with selected YMD values.
111 // TODO: Consider moving this to a date service...
112 localDateFromYmd(ymd: string): Date {
113 const parts = ymd.split('-');
115 Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
126 writeValue(value: Date) {
129 year: value.getFullYear(),
130 month: value.getMonth() + 1,
136 registerOnChange(fn) {
137 this.propagateChange = fn;
140 registerOnTouched(fn) {
141 this.propagateTouch = fn;