LP1821382 Angular boolean yes/no display component
authorBill Erickson <berickxx@gmail.com>
Wed, 20 Mar 2019 16:06:20 +0000 (12:06 -0400)
committerDan Wells <dbw2@calvin.edu>
Wed, 29 May 2019 19:30:50 +0000 (15:30 -0400)
Simple component that accepts a boolean value and displays a yes/no
badge.  Added as the default handler for boolean columsn in the grid.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Dan Wells <dbw2@calvin.edu>
Open-ILS/src/eg2/src/app/common.module.ts
Open-ILS/src/eg2/src/app/core/format.service.ts
Open-ILS/src/eg2/src/app/share/grid/grid-body-cell.component.html
Open-ILS/src/eg2/src/app/share/grid/grid-column.component.ts
Open-ILS/src/eg2/src/app/share/grid/grid.ts
Open-ILS/src/eg2/src/app/share/util/bool.component.ts [new file with mode: 0644]

index f1d4467..a4e4026 100644 (file)
@@ -25,6 +25,7 @@ import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
 import {PromptDialogComponent} from '@eg/share/dialog/prompt.component';
 import {ProgressInlineComponent} from '@eg/share/dialog/progress-inline.component';
 import {ProgressDialogComponent} from '@eg/share/dialog/progress.component';
 import {PromptDialogComponent} from '@eg/share/dialog/prompt.component';
 import {ProgressInlineComponent} from '@eg/share/dialog/progress-inline.component';
 import {ProgressDialogComponent} from '@eg/share/dialog/progress.component';
+import {BoolDisplayComponent} from '@eg/share/util/bool.component';
 
 @NgModule({
   declarations: [
 
 @NgModule({
   declarations: [
@@ -35,6 +36,7 @@ import {ProgressDialogComponent} from '@eg/share/dialog/progress.component';
     PromptDialogComponent,
     ProgressInlineComponent,
     ProgressDialogComponent,
     PromptDialogComponent,
     ProgressInlineComponent,
     ProgressDialogComponent,
+    BoolDisplayComponent,
     FormatValuePipe
   ],
   imports: [
     FormatValuePipe
   ],
   imports: [
@@ -55,6 +57,7 @@ import {ProgressDialogComponent} from '@eg/share/dialog/progress.component';
     PromptDialogComponent,
     ProgressInlineComponent,
     ProgressDialogComponent,
     PromptDialogComponent,
     ProgressInlineComponent,
     ProgressDialogComponent,
+    BoolDisplayComponent,
     FormatValuePipe
   ]
 })
     FormatValuePipe
   ]
 })
index 8108eec..d2b2ce5 100644 (file)
@@ -119,7 +119,8 @@ export class FormatService {
 
             case 'bool':
                 // Slightly better than a bare 't' or 'f'.
 
             case 'bool':
                 // Slightly better than a bare 't' or 'f'.
-                // Should probably add a global true/false string.
+                // Note the caller is better off using an <eg-bool/> for
+                // boolean display.
                 return Boolean(
                     value === 't' || value === 1 ||
                     value === '1' || value === true
                 return Boolean(
                     value === 't' || value === 1 ||
                     value === '1' || value === true
index 6dc4a99..921fafc 100644 (file)
@@ -4,7 +4,14 @@
   placement="top-left"
   class="{{context.cellClassCallback(row, column)}}"
   triggers="mouseenter:mouseleave">
   placement="top-left"
   class="{{context.cellClassCallback(row, column)}}"
   triggers="mouseenter:mouseleave">
-  {{context.getRowColumnValue(row, column)}}
+  <ng-container *ngIf="column.datatype == 'bool'">
+    <eg-bool [value]="context.getRowColumnValue(row, column)"
+      [ternary]="column.ternaryBool">
+    </eg-bool>
+  </ng-container>
+  <ng-container *ngIf="column.datatype != 'bool'">
+    {{context.getRowColumnValue(row, column)}}
+  </ng-container>
 </span>
 <span *ngIf="column.cellTemplate" 
   class="{{context.cellClassCallback(row, column)}}"
 </span>
 <span *ngIf="column.cellTemplate" 
   class="{{context.cellClassCallback(row, column)}}"
index 76a89f6..fc18fc7 100644 (file)
@@ -24,6 +24,9 @@ export class GridColumnComponent implements OnInit {
     @Input() datatype: string;
     @Input() multiSortable: boolean;
 
     @Input() datatype: string;
     @Input() multiSortable: boolean;
 
+    // If true, boolean fields support 3 values: true, false, null (unset)
+    @Input() ternaryBool: boolean;
+
     // Display date and time when datatype = timestamp
     @Input() datePlusTime: boolean;
 
     // Display date and time when datatype = timestamp
     @Input() datePlusTime: boolean;
 
@@ -57,6 +60,7 @@ export class GridColumnComponent implements OnInit {
         col.isMultiSortable = this.multiSortable;
         col.datatype = this.datatype;
         col.datePlusTime = this.datePlusTime;
         col.isMultiSortable = this.multiSortable;
         col.datatype = this.datatype;
         col.datePlusTime = this.datePlusTime;
+        col.ternaryBool = this.ternaryBool;
         col.isAuto = false;
         this.grid.context.columnSet.add(col);
     }
         col.isAuto = false;
         this.grid.context.columnSet.add(col);
     }
index 64f3321..7cf5f53 100644 (file)
@@ -26,6 +26,7 @@ export class GridColumn {
     idlFieldDef: any;
     datatype: string;
     datePlusTime: boolean;
     idlFieldDef: any;
     datatype: string;
     datePlusTime: boolean;
+    ternaryBool: boolean;
     cellTemplate: TemplateRef<any>;
     cellContext: any;
     isIndex: boolean;
     cellTemplate: TemplateRef<any>;
     cellContext: any;
     isIndex: boolean;
@@ -658,6 +659,12 @@ export class GridContext {
             val = this.getObjectFieldValue(row, col.name);
         }
 
             val = this.getObjectFieldValue(row, col.name);
         }
 
+        if (col.datatype === 'bool') {
+            // Avoid string-ifying bools so we can use an <eg-bool/>
+            // in the grid template.
+            return val;
+        }
+
         return this.format.transform({
             value: val,
             idlClass: col.idlClass,
         return this.format.transform({
             value: val,
             idlClass: col.idlClass,
diff --git a/Open-ILS/src/eg2/src/app/share/util/bool.component.ts b/Open-ILS/src/eg2/src/app/share/util/bool.component.ts
new file mode 100644 (file)
index 0000000..37d2e8d
--- /dev/null
@@ -0,0 +1,39 @@
+import {Component, Input} from '@angular/core';
+
+/* Simple component to render a boolean value as human-friendly text */
+
+@Component({
+    selector: 'eg-bool',
+    template: `
+      <ng-container>
+        <span *ngIf="value" class="badge badge-success" i18n>Yes</span>
+        <span *ngIf="value == false" class="badge badge-secondary" i18n>No</span>
+        <ng-container *ngIf="value === null">
+          <span *ngIf="ternary" class="badge badge-light" i18n>Unset</span>
+          <span *ngIf="!ternary"> </span>
+      </ng-container>`
+})
+export class BoolDisplayComponent {
+
+    _value: boolean;
+    @Input() set value(v: boolean) {
+        this._value = v;
+    }
+    get value(): boolean {
+        return this._value;
+    }
+
+    // If true, a null value displays as unset.
+    // If false, a null value displays as an empty string.
+    _ternary: boolean;
+    @Input() set ternary(t: boolean) {
+        this._ternary = t;
+    }
+    get ternary(): boolean {
+        return this._ternary;
+    }
+
+    constructor() {
+        this.value = null;
+    }
+}
\ No newline at end of file