From 1145542d9a0f3386ba38ef1546e25a1af2ddcf17 Mon Sep 17 00:00:00 2001 From: Galen Charlton Date: Wed, 26 Feb 2020 10:39:10 -0500 Subject: [PATCH] eg-combobox: add per-IDL-class formatting This patch teaches eg-combobox to apply display templates and label formatters for when idlClass is set. Currently templates are defined for acqf and acpl. Signed-off-by: Galen Charlton --- .../src/app/share/combobox/combobox.component.html | 9 ++- .../src/app/share/combobox/combobox.component.ts | 64 ++++++++++++++++++++-- .../src/eg2/src/app/share/common-widgets.module.ts | 3 +- 3 files changed, 69 insertions(+), 7 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 83df22e20a..16f2bf6d94 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 @@ -4,6 +4,13 @@ {{r.label || r.id}} + + {{r.fm.code()}} ({{r.fm.year()}}) + + + {{r.fm.name()}} ({{getOrgShortname(r.fm.owning_lib())}}) + +
*/ import {Component, OnInit, Input, Output, ViewChild, + Directive, ViewChildren, QueryList, AfterViewInit, TemplateRef, EventEmitter, ElementRef, forwardRef} from '@angular/core'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; import {Observable, of, Subject} from 'rxjs'; import {map, tap, reduce, mergeMap, mapTo, debounceTime, distinctUntilChanged, merge, filter} from 'rxjs/operators'; import {NgbTypeahead, NgbTypeaheadSelectItemEvent} from '@ng-bootstrap/ng-bootstrap'; import {StoreService} from '@eg/core/store.service'; -import {IdlService} from '@eg/core/idl.service'; +import {IdlService, IdlObject} from '@eg/core/idl.service'; import {PcrudService} from '@eg/core/pcrud.service'; +import {OrgService} from '@eg/core/org.service'; export interface ComboboxEntry { id: any; // If no label is provided, the 'id' value is used. label?: string; freetext?: boolean; + fm?: IdlObject; +} + +@Directive({ + selector: 'ng-template[idlClass]' +}) +export class IdlClassTemplateDirective { + @Input('idlClass') idlClass: string; + constructor(public template: TemplateRef) {} } @Component({ @@ -33,13 +44,15 @@ export interface ComboboxEntry { multi: true }] }) -export class ComboboxComponent implements ControlValueAccessor, OnInit { +export class ComboboxComponent implements ControlValueAccessor, OnInit, AfterViewInit { selected: ComboboxEntry; click$: Subject; entrylist: ComboboxEntry[]; @ViewChild('instance', { static: true }) instance: NgbTypeahead; + @ViewChild('defaultDisplayTemplate', { static: true}) t: TemplateRef; + @ViewChildren(IdlClassTemplateDirective) idlClassTemplates: QueryList; // Applies a name attribute to the input. // Useful in forms. @@ -88,7 +101,8 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit { .subscribe(rec => { this.entrylist = [{ id: id, - label: rec[this.idlField]() + label: this.getFmRecordLabel(rec), + fm: rec }]; this.selected = this.entrylist.filter(e => e.id === id)[0]; }); @@ -155,11 +169,15 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit { propagateChange = (_: any) => {}; propagateTouch = () => {}; + idlDisplayTemplateMap: { [key: string]: TemplateRef } = {}; + getFmRecordLabel: (fm: IdlObject) => string; + constructor( private elm: ElementRef, private store: StoreService, private idl: IdlService, private pcrud: PcrudService, + private org: OrgService, ) { this.entrylist = []; this.asyncIds = {}; @@ -171,6 +189,26 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit { const display = result.label || result.id; return (display + '').trim(); }; + + this.getFmRecordLabel = (fm: IdlObject) => { + // FIXME: it would be cleaner if we could somehow use + // the per-IDL-class ng-templates directly + switch (this.idlClass) { + case 'acqf': + return fm.code() + ' (' + fm.year() + ')'; + break; + case 'acpl': + return fm.name() + ' (' + this.getOrgShortname(fm.owning_lib()) + ')'; + break; + default: + const field = this.idlField; + if (this.idlIncludeLibraryInLabel) { + return fm[field]() + ' (' + fm[this.idlIncludeLibraryInLabel]().shortname() + ')'; + } else { + return fm[field](); + } + } + }; } ngOnInit() { @@ -201,22 +239,38 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit { return this.pcrud.search(this.idlClass, args, extra_args).pipe(map(data => { return { id: data[pkeyField](), - label: data[field]() + ' (' + data[this.idlIncludeLibraryInLabel]().shortname() + ')' + label: this.getFmRecordLabel(data), + fm: data }; })); } else { return this.pcrud.search(this.idlClass, args, extra_args).pipe(map(data => { - return {id: data[pkeyField](), label: data[field]()}; + return {id: data[pkeyField](), label: this.getFmRecordLabel(data), fm: data}; })); } }; } } + ngAfterViewInit() { + this.idlDisplayTemplateMap = this.idlClassTemplates.reduce((acc, cur) => { + acc[cur.idlClass] = cur.template; + return acc; + }, {}); + } + onClick($event) { this.click$.next($event.target.value); } + getOrgShortname(ou: any) { + if (typeof ou === 'object') { + return ou.shortname(); + } else { + return this.org.get(ou).shortname(); + } + } + openMe($event) { // Give the input a chance to focus then fire the click // handler to force open the typeahead diff --git a/Open-ILS/src/eg2/src/app/share/common-widgets.module.ts b/Open-ILS/src/eg2/src/app/share/common-widgets.module.ts index 76e0ff0ae8..090e5455b5 100644 --- a/Open-ILS/src/eg2/src/app/share/common-widgets.module.ts +++ b/Open-ILS/src/eg2/src/app/share/common-widgets.module.ts @@ -8,7 +8,7 @@ import {CommonModule} from '@angular/common'; import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {NgbModule} from '@ng-bootstrap/ng-bootstrap'; import {EgCoreModule} from '@eg/core/core.module'; -import {ComboboxComponent} from '@eg/share/combobox/combobox.component'; +import {ComboboxComponent, IdlClassTemplateDirective} from '@eg/share/combobox/combobox.component'; import {ComboboxEntryComponent} from '@eg/share/combobox/combobox-entry.component'; import {DateSelectComponent} from '@eg/share/date-select/date-select.component'; import {OrgSelectComponent} from '@eg/share/org-select/org-select.component'; @@ -28,6 +28,7 @@ import {IntervalInputComponent} from '@eg/share/interval-input/interval-input.co DateTimeSelectComponent, FileReaderComponent, IntervalInputComponent, + IdlClassTemplateDirective ], imports: [ CommonModule, -- 2.11.0