]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/eg2/src/app/share/date-select/date-select.component.ts
LP1831390: combobox and date-select implement ControlValueAccessor
[Evergreen.git] / Open-ILS / src / eg2 / src / app / share / date-select / date-select.component.ts
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';
4
5 /**
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
9  */
10
11 @Component({
12   selector: 'eg-date-select',
13   templateUrl: './date-select.component.html',
14   styleUrls: ['date-select.component.css'],
15   providers: [ {
16       provide: NG_VALUE_ACCESSOR,
17       useExisting: forwardRef(() => DateSelectComponent),
18       multi: true
19   } ]
20 })
21 export class DateSelectComponent implements OnInit, ControlValueAccessor {
22
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;
28     @Input() domId = '';
29     @Input() disabled: boolean;
30     @Input() readOnly: boolean;
31
32     current: NgbDateStruct;
33
34     @Output() onChangeAsDate: EventEmitter<Date>;
35     @Output() onChangeAsIso: EventEmitter<string>;
36     @Output() onChangeAsYmd: EventEmitter<string>;
37     @Output() onCleared: EventEmitter<string>;
38
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')}`;
44     }
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();
51         return iso;
52     }
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);
58         return date;
59     }
60
61     constructor() {
62         this.onChangeAsDate = new EventEmitter<Date>();
63         this.onChangeAsIso = new EventEmitter<string>();
64         this.onChangeAsYmd = new EventEmitter<string>();
65         this.onCleared = new EventEmitter<string>();
66     }
67
68     ngOnInit() {
69
70         if (this.initialYmd) {
71             this.initialDate = this.localDateFromYmd(this.initialYmd);
72
73         } else if (this.initialIso) {
74             this.initialDate = new Date(this.initialIso);
75         }
76
77         if (this.initialDate) {
78             this.current = {
79                 year: this.initialDate.getFullYear(),
80                 month: this.initialDate.getMonth() + 1,
81                 day: this.initialDate.getDate()
82             };
83         }
84     }
85
86     isValidDate(dt: NgbDateStruct): dt is NgbDateStruct {
87         return (<NgbDateStruct>dt).year !== undefined;
88     }
89
90     onDateEnter() {
91         if (this.current === null) {
92             this.onCleared.emit('cleared');
93         } else if (this.isValidDate(this.current)) {
94             this.onDateSelect(this.current);
95         }
96         // ignoring invalid input for now
97     }
98
99     onDateSelect(evt) {
100         const ymd = `${evt.year}-${String(evt.month).padStart(2, '0')}-${String(evt.day).padStart(2, '0')}`;
101         const date = this.localDateFromYmd(ymd);
102         const iso = date.toISOString();
103         this.onChangeAsDate.emit(date);
104         this.onChangeAsYmd.emit(ymd);
105         this.propagateChange(ymd);
106         this.onChangeAsIso.emit(iso);
107     }
108
109     // Create a date in the local time zone with selected YMD values.
110     // TODO: Consider moving this to a date service...
111     localDateFromYmd(ymd: string): Date {
112         const parts = ymd.split('-');
113         return new Date(
114             Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
115     }
116
117     reset() {
118         this.current = {
119             year: null,
120             month: null,
121             day: null
122         };
123     }
124
125     writeValue(value: string) {
126         if (value !== undefined) {
127             this.initialYmd = value;
128         }
129     }
130
131     propagateChange = (_: any) => {};
132
133     registerOnChange(fn) {
134         this.propagateChange = fn;
135     }
136
137     registerOnTouched() { }
138 }
139
140