LP#1831780: various improvements to the Angular date-select widget
[Evergreen.git] / Open-ILS / src / eg2 / src / app / share / date-select / date-select.component.ts
1 import {Component, OnInit, Input, Output, ViewChild, EventEmitter} from '@angular/core';
2 import {NgbDateStruct} from '@ng-bootstrap/ng-bootstrap';
3
4 /**
5  * RE: displaying locale dates in the input field:
6  * https://github.com/ng-bootstrap/ng-bootstrap/issues/754
7  * https://stackoverflow.com/questions/40664523/angular2-ngbdatepicker-how-to-format-date-in-inputfield
8  */
9
10 @Component({
11   selector: 'eg-date-select',
12   templateUrl: './date-select.component.html',
13   styleUrls: ['date-select.component.css']
14 })
15 export class DateSelectComponent implements OnInit {
16
17     @Input() initialIso: string; // ISO string
18     @Input() initialYmd: string; // YYYY-MM-DD (uses local time zone)
19     @Input() initialDate: Date;  // Date object
20     @Input() required: boolean;
21     @Input() fieldName: string;
22     @Input() domId = '';
23
24     _disabled: boolean;
25     @Input() set disabled(d: boolean) {
26         this._disabled = d;
27     }
28
29     current: NgbDateStruct;
30
31     @Output() onChangeAsDate: EventEmitter<Date>;
32     @Output() onChangeAsIso: EventEmitter<string>;
33     @Output() onChangeAsYmd: EventEmitter<string>;
34     @Output() onCleared: EventEmitter<string>;
35
36     // convenience methods to access current selected date
37     currentAsYmd(): string {
38         if (this.current == null) { return null; }
39         if (!this.isValidDate(this.current)) { return null; }
40         return `${this.current.year}-${String(this.current.month).padStart(2, '0')}-${String(this.current.day).padStart(2, '0')}`;
41     }
42     currentAsIso(): string {
43         if (this.current == null) { return null; }
44         if (!this.isValidDate(this.current)) { return null; }
45         const ymd = `${this.current.year}-${String(this.current.month).padStart(2, '0')}-${String(this.current.day).padStart(2, '0')}`;
46         const date = this.localDateFromYmd(ymd);
47         const iso = date.toISOString();
48         return iso;
49     }
50     currentAsDate(): Date {
51         if (this.current == null) { return null; }
52         if (!this.isValidDate(this.current)) { return null; }
53         const ymd = `${this.current.year}-${String(this.current.month).padStart(2, '0')}-${String(this.current.day).padStart(2, '0')}`;
54         const date = this.localDateFromYmd(ymd);
55         return date;
56     }
57
58     constructor() {
59         this.onChangeAsDate = new EventEmitter<Date>();
60         this.onChangeAsIso = new EventEmitter<string>();
61         this.onChangeAsYmd = new EventEmitter<string>();
62         this.onCleared = new EventEmitter<string>();
63     }
64
65     ngOnInit() {
66
67         if (this.initialYmd) {
68             this.initialDate = this.localDateFromYmd(this.initialYmd);
69
70         } else if (this.initialIso) {
71             this.initialDate = new Date(this.initialIso);
72         }
73
74         if (this.initialDate) {
75             this.current = {
76                 year: this.initialDate.getFullYear(),
77                 month: this.initialDate.getMonth() + 1,
78                 day: this.initialDate.getDate()
79             };
80         }
81     }
82
83     isValidDate(dt: NgbDateStruct): dt is NgbDateStruct {
84         return (<NgbDateStruct>dt).year !== undefined;
85     }
86
87     onDateEnter() {
88         if (this.current === null) {
89             this.onCleared.emit('cleared');
90         } else if (this.isValidDate(this.current)) {
91             this.onDateSelect(this.current);
92         }
93         // ignoring invalid input for now
94     }
95
96     onDateSelect(evt) {
97         const ymd = `${evt.year}-${String(evt.month).padStart(2, '0')}-${String(evt.day).padStart(2, '0')}`;
98         const date = this.localDateFromYmd(ymd);
99         const iso = date.toISOString();
100         this.onChangeAsDate.emit(date);
101         this.onChangeAsYmd.emit(ymd);
102         this.onChangeAsIso.emit(iso);
103     }
104
105     // Create a date in the local time zone with selected YMD values.
106     // TODO: Consider moving this to a date service...
107     localDateFromYmd(ymd: string): Date {
108         const parts = ymd.split('-');
109         return new Date(
110             Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
111     }
112
113     reset() {
114         this.current = {
115             year: null,
116             month: null,
117             day: null
118         };
119     }
120
121 }
122
123