LP1888723 Support disabling select entries in combobox
authorBill Erickson <berickxx@gmail.com>
Wed, 3 Mar 2021 15:52:36 +0000 (10:52 -0500)
committerGalen Charlton <gmc@equinoxOLI.org>
Sun, 15 Aug 2021 23:57:01 +0000 (19:57 -0400)
Adds a new @Input() disableEntries: any[] for tracking identifier
values in the combobox that should be marked as disabled / unselectable.

Substantive updates during rebasing made by Galen Charlton.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Ruth Frasur <rfrasur@library.in.gov>
Signed-off-by: Galen Charlton <gmc@equinoxOLI.org>
Open-ILS/src/eg2/src/app/share/combobox/combobox.component.html
Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts

index deb7464..c48d981 100644 (file)
@@ -1,14 +1,15 @@
 
-<!-- todo disabled -->
 <ng-template #defaultDisplayTemplate let-r="result">
-{{r.label || r.id}}
+  <span id="{{domId}}-{{r.id}}">{{r.label}}</span>
 </ng-template>
 
 <ng-template #acqfTemplate egIdlClass="acqf" let-r="result">
-  {{r.fm.code()}} ({{r.fm.year()}}) ({{getOrgShortname(r.fm.org())}})
+  <span id="{{domId}}-{{r.id}}">{{r.fm.code()}} ({{r.fm.year()}}) ({{getOrgShortname(r.fm.org())}})</span>
 </ng-template>
 <ng-template #acplTemplate egIdlClass="acpl" let-r="result">
-  {{r.fm.name()}} ({{getOrgShortname(r.fm.owning_lib())}})
+  <span id="{{domId}}-{{r.id}}">
+    {{r.fm.name()}} ({{getOrgShortname(r.fm.owning_lib())}})
+  </span>
 </ng-template>
 
 <div class="d-flex">
index fb2d81b..7df59e8 100644 (file)
@@ -23,6 +23,7 @@ export interface ComboboxEntry {
   freetext?: boolean;
   userdata?: any; // opaque external value; ignored by this component.
   fm?: IdlObject;
+  disabled?: boolean;
 }
 
 @Directive({
@@ -89,6 +90,9 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterVie
         this.isRequired = r;
     }
 
+    // Array of entry identifiers to disable in the selector
+    @Input() disableEntries: any[] = [];
+
     // Disable the input
     isDisabled: boolean;
     @Input() set disabled(d: boolean) {
@@ -125,7 +129,8 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterVie
                     this.entrylist = [{
                         id: id,
                         label: this.getFmRecordLabel(rec),
-                        fm: rec
+                        fm: rec,
+                        disabled : this.disableEntries.includes(id)
                     }];
                     this.selected = this.entrylist.filter(e => e.id === id)[0];
                 });
@@ -492,6 +497,18 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterVie
         });
     }
 
+    // NgbTypeahead doesn't offer a way to style the dropdown
+    // button directly, so we have to reach up and style it ourselves.
+    applyDisableStyle() {
+        this.disableEntries.forEach(id => {
+            const node = document.getElementById(`${this.domId}-${id}`);
+            if (node) {
+                const button = node.parentNode as HTMLElement;
+                button.classList.add('disabled');
+            }
+        });
+    }
+
     filter = (text$: Observable<string>): Observable<ComboboxEntry[]> => {
         return text$.pipe(
             debounceTime(200),
@@ -520,10 +537,17 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterVie
                     if (this.asyncDataSource) {
                         term = '';
                     } else {
+                        // Give the typeahead a chance to open before applying
+                        // the disabled entry styling.
+                        setTimeout(() => this.applyDisableStyle());
                         return this.entrylist;
                     }
                 }
 
+                // Give the typeahead a chance to open before applying
+                // the disabled entry styling.
+                setTimeout(() => this.applyDisableStyle());
+
                 // Filter entrylist whose labels substring-match the
                 // text entered.
                 return this.entrylist.filter(entry => {