LP1840782 <eg-date-select-native /> component user/berick/lp1840782-native-date-select-v2
authorBill Erickson <berickxx@gmail.com>
Thu, 7 Oct 2021 19:42:02 +0000 (15:42 -0400)
committerBill Erickson <berickxx@gmail.com>
Thu, 7 Oct 2021 19:42:45 +0000 (15:42 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/share/date-select-native/date-select-native.component.css [new file with mode: 0644]
Open-ILS/src/eg2/src/app/share/date-select-native/date-select-native.component.html
Open-ILS/src/eg2/src/app/share/date-select-native/date-select-native.component.ts
Open-ILS/src/eg2/src/styles.css

diff --git a/Open-ILS/src/eg2/src/app/share/date-select-native/date-select-native.component.css b/Open-ILS/src/eg2/src/app/share/date-select-native/date-select-native.component.css
new file mode 100644 (file)
index 0000000..8ce0079
--- /dev/null
@@ -0,0 +1,9 @@
+
+/* Apply the invalid styling directly to the input instead of the
+ * component container node.  Otherwise, the border displays above
+ * the date input instead of to the left.
+ */
+.ng-invalid {
+  border-left: 5px solid #FA787E;
+}
+
index a92fe3e..23f9e9c 100644 (file)
@@ -2,10 +2,12 @@
   type="date"
   id="{{domId}}" 
   name="{{fieldName}}"
+  class="form-control"
   [min]="min"
   [max]="max"
   [required]="required"
   [disabled]="disabled"
+  [ngClass]="{'ng-invalid': invalid()}"
   (blur)="propagateTouch()"
   (change)="inputChange($event)"
 />
index 42f2da3..6cafad9 100644 (file)
@@ -6,6 +6,7 @@ import {DateUtil} from '@eg/share/util/date';
 @Component({
   selector: 'eg-date-select-native',
   templateUrl: './date-select-native.component.html',
+  styleUrls: ['./date-select-native.component.css'],
   providers: [{
       provide: NG_VALUE_ACCESSOR,
       useExisting: forwardRef(() => DateSelectNativeComponent),
@@ -20,14 +21,16 @@ export class DateSelectNativeComponent implements OnInit, ControlValueAccessor {
     @Input() disabled = false;  // Also works for readOnly
     @Input() min = '';          // YYYY-MM-DD
     @Input() max = '';          // YYYY-MM-DD
+    @Input() noFuture = false;  // sets max to now
+    @Input() noPast = false;    // sets min to now
     @Input() domId = 'eg-date-select-native-' + DateSelectNativeComponent.domAutoId++;
 
     // Emits YYYY-MM-DD on value change, null on empty.
-    @Output() dateChange: EventEmitter<string> = new EventEmitter<string>();
+    @Output() valueChange: EventEmitter<string> = new EventEmitter<string>();
     // Emits Date object
-    @Output() dateChangeAsDate: EventEmitter<Date> = new EventEmitter<Date>();
+    @Output() valueChangeAsDate: EventEmitter<Date> = new EventEmitter<Date>();
     // Emits ISO8601 date string
-    @Output() dateChangeAsIso: EventEmitter<string> = new EventEmitter<string>();
+    @Output() valueChangeAsIso: EventEmitter<string> = new EventEmitter<string>();
 
     // Stub functions required by ControlValueAccessor
     propagateChange = (_: any) => {};
@@ -35,27 +38,55 @@ export class DateSelectNativeComponent implements OnInit, ControlValueAccessor {
 
     constructor() { }
 
-    ngOnInit() { }
+    ngOnInit() {
+        if (this.noFuture) {
+            this.max = DateUtil.localYmdFromDate();
+        }
+
+        if (this.noPast) {
+            this.min = DateUtil.localYmdFromDate();
+        }
+    }
 
     input(): HTMLInputElement {
         return document.getElementById(this.domId) as HTMLInputElement;
     }
 
+    invalid(): boolean {
+        if (!this.input()) { return false; }
+
+        let value = this.input().value;
+
+        if (this.required && !value) { return true; }
+
+        // <input type="date"/> will prevent selection of out-of-bounds
+        // dates, but it does not prevent the user from manually
+        // entering such a date.
+        const nowYmd = DateUtil.localYmdFromDate();
+
+        if (this.noFuture && value > nowYmd) { return true; }
+
+        if (this.noPast && value < nowYmd) { return true; }
+
+        return false;
+    }
+
     inputChange(evt: Event) {
         const value = this.input().value;
         this.propagateChange(value);
 
         if (!value) {
-            this.dateChange.emit(null);
-            this.dateChangeAsDate.emit(null);
-            this.dateChangeAsIso.emit(null);
+
+            this.valueChange.emit(null);
+            this.valueChangeAsDate.emit(null);
+            this.valueChangeAsIso.emit(null);
 
         } else {
 
             let date = DateUtil.localDateFromYmd(value);
-            this.dateChange.emit(value);
-            this.dateChangeAsDate.emit(date);
-            this.dateChangeAsIso.emit(date.toISOString());
+            this.valueChange.emit(value);
+            this.valueChangeAsDate.emit(date);
+            this.valueChangeAsIso.emit(date.toISOString());
         }
     }
 
index 66c6f68..26a5af4 100644 (file)
@@ -169,11 +169,11 @@ h5 {font-size: .95rem}
  * Required valid fields are left-border styled in green-ish.
  * Invalid fields are left-border styled in red-ish.
  */
-.form-validated .ng-valid[required]:not(eg-combobox):not(eg-date-select), 
+.form-validated .ng-valid[required]:not(eg-combobox):not(eg-date-select):not(eg-date-select-native)
 .form-validated .ng-valid.required, input[formcontrolname].ng-valid {
   border-left: 5px solid #78FA89;
 }
-.form-validated .ng-invalid:not(form):not(eg-combobox):not(eg-date-select),
+.form-validated .ng-invalid:not(form):not(eg-combobox):not(eg-date-select):not(eg-date-select-native),
 input[formcontrolname].ng-invalid {
   border-left: 5px solid #FA787E;
 }