From ad4782b1bbab913a109771e695611472c7e7ed71 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Wed, 12 May 2021 12:00:07 -0400 Subject: [PATCH] LP1842763 Combobox readonly, domId, and more * Readonly support which just displays the selected value. * domId in put support * smallFormContron option * append to the IDL query with a new idlQueryAnd input * Support for applying a freetext startId value * Fixes issues with click-to-show-all support Signed-off-by: Bill Erickson --- .../src/app/share/combobox/combobox.component.html | 55 ++++++++++------ .../src/app/share/combobox/combobox.component.ts | 76 ++++++++++++++++------ 2 files changed, 89 insertions(+), 42 deletions(-) diff --git a/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.html b/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.html index d2280811e3..6d2131ea6e 100644 --- a/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.html +++ b/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.html @@ -11,25 +11,38 @@ {{r.fm.name()}} ({{getOrgShortname(r.fm.owning_lib())}}) -
- -
- keyboard_arrow_up - keyboard_arrow_down + + <Unset> + + + + + + +
+ +
+ keyboard_arrow_up + keyboard_arrow_down +
-
+ diff --git a/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts b/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts index d21ad5f916..7d03b2f938 100644 --- a/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts +++ b/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts @@ -46,16 +46,21 @@ export class IdlClassTemplateDirective { multi: true }] }) -export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterViewInit, OnChanges { +export class ComboboxComponent + implements ControlValueAccessor, OnInit, AfterViewInit, OnChanges { + + static domIdAuto = 0; selected: ComboboxEntry; click$: Subject; entrylist: ComboboxEntry[]; - @ViewChild('instance', { static: true }) instance: NgbTypeahead; - @ViewChild('defaultDisplayTemplate', { static: true}) defaultDisplayTemplate: TemplateRef; + @ViewChild('instance', {static: false}) instance: NgbTypeahead; + @ViewChild('defaultDisplayTemplate', {static: true}) defaultDisplayTemplate: TemplateRef; @ViewChildren(IdlClassTemplateDirective) idlClassTemplates: QueryList; + @Input() domId = 'eg-combobox-' + ComboboxComponent.domIdAuto++; + // Applies a name attribute to the input. // Useful in forms. @Input() name: string; @@ -69,6 +74,9 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterVie @Input() inputSize: number = null; + // If true, applies form-control-sm CSS + @Input() smallFormControl = false; + // Add a 'required' attribute to the input isRequired: boolean; @Input() set required(r: boolean) { @@ -88,13 +96,24 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterVie @Input() idlClass: string; @Input() startIdFiresOnChange: boolean; + // This will be appended to the async data retrieval query + // when fetching objects by idlClass. + @Input() idlQueryAnd: {[field: string]: any}; + + // Display the selected value as text instead of within + // the typeahead + @Input() readOnly = false; + // Allow the selected entry ID to be passed via the template // This does NOT not emit onChange events. @Input() set selectedId(id: any) { if (id === undefined) { return; } // clear on explicit null - if (id === null) { this.selected = null; } + if (id === null) { + this.selected = null; + return; + } if (this.entrylist.length) { this.selected = this.entrylist.filter(e => e.id === id)[0]; @@ -239,6 +258,9 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterVie const args = {}; const extra_args = { order_by : {} }; args[field] = {'ilike': `%${term}%`}; // could -or search on label + if (this.idlQueryAnd) { + Object.assign(args, this.idlQueryAnd); + } extra_args['order_by'][this.idlClass] = field; extra_args['limit'] = 100; if (this.idlIncludeLibraryInLabel) { @@ -358,8 +380,7 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterVie // Apply a default selection where needed applySelection() { - if (this.startId !== null && - this.entrylist && !this.defaultSelectionApplied) { + if (this.entrylist && !this.defaultSelectionApplied) { const entry = this.entrylist.filter(e => e.id === this.startId)[0]; @@ -389,6 +410,7 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterVie } addAsyncEntry(entry: ComboboxEntry) { + if (!entry) { return; } // Avoid duplicate async entries if (!this.asyncIds['' + entry.id]) { this.asyncIds['' + entry.id] = true; @@ -407,13 +429,25 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterVie if (typeof this.selected === 'string') { if (this.allowFreeText && this.selected !== '') { - // Free text entered which does not match a known entry - // translate it into a dummy ComboboxEntry - this.selected = { - id: null, - label: this.selected, - freetext: true - }; + const freeText = this.entrylist.filter(e => e.id === null)[0]; + + if (freeText) { + + // If we already had a free text entry, just replace + // the label with the new value + freeText.label = this.selected; + this.selected = freeText; + + } else { + + // Free text entered which does not match a known entry + // translate it into a dummy ComboboxEntry + this.selected = { + id: null, + label: this.selected, + freetext: true + }; + } } else { @@ -442,12 +476,14 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterVie return of(term); } - let searchTerm: string; - searchTerm = term; - if (searchTerm === '_CLICK_') { + let searchTerm = term; + if (term === '_CLICK_') { if (this.asyncSupportsEmptyTermClick) { + // Search for "all", but retain and propage the _CLICK_ + // term so the filter knows to open the selector searchTerm = ''; } else { + // Skip the final filter map and display nothing. return of(); } } @@ -457,7 +493,7 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterVie (entry: ComboboxEntry) => this.addAsyncEntry(entry), err => {}, () => { - observer.next(searchTerm); + observer.next(term); observer.complete(); } ); @@ -487,10 +523,8 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterVie // click action occurred. if (term === '') { return []; } - // In sync-data mode, a click displays the full list. - if (term === '_CLICK_' && !this.asyncDataSource) { - return this.entrylist; - } + // If we make it this far, _CLICK_ means show everything. + if (term === '_CLICK_') { term = ''; } // Filter entrylist whose labels substring-match the // text entered. -- 2.11.0