From: Bill Erickson Date: Fri, 29 Jun 2018 19:56:20 +0000 (-0400) Subject: LP#1775466 Generic typeahead component X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=8fa770226405df43118c7fe3b90e2ab5e7491a9f;p=working%2FEvergreen.git LP#1775466 Generic typeahead component Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/src/eg2/src/app/share/org-select/org-select.component.ts b/Open-ILS/src/eg2/src/app/share/org-select/org-select.component.ts index 8055616e29..99ea3987b8 100644 --- a/Open-ILS/src/eg2/src/app/share/org-select/org-select.component.ts +++ b/Open-ILS/src/eg2/src/app/share/org-select/org-select.component.ts @@ -1,3 +1,4 @@ +/** TODO PORT ME TO */ import {Component, OnInit, Input, Output, ViewChild, EventEmitter} from '@angular/core'; import {Observable} from 'rxjs/Observable'; import {map} from 'rxjs/operators/map'; diff --git a/Open-ILS/src/eg2/src/app/share/typeahead/typeahead.component.html b/Open-ILS/src/eg2/src/app/share/typeahead/typeahead.component.html new file mode 100644 index 0000000000..219b2d381b --- /dev/null +++ b/Open-ILS/src/eg2/src/app/share/typeahead/typeahead.component.html @@ -0,0 +1,17 @@ + + + +{{r.label}} + + + diff --git a/Open-ILS/src/eg2/src/app/share/typeahead/typeahead.component.ts b/Open-ILS/src/eg2/src/app/share/typeahead/typeahead.component.ts new file mode 100644 index 0000000000..0aad3d70db --- /dev/null +++ b/Open-ILS/src/eg2/src/app/share/typeahead/typeahead.component.ts @@ -0,0 +1,118 @@ +import {Component, OnInit, Input, Output, ViewChild, EventEmitter} from '@angular/core'; +import {Observable} from 'rxjs/Observable'; +import {map} from 'rxjs/operators/map'; +import {mapTo} from 'rxjs/operators/mapTo'; +import {debounceTime} from 'rxjs/operators/debounceTime'; +import {distinctUntilChanged} from 'rxjs/operators/distinctUntilChanged'; +import {merge} from 'rxjs/operators/merge'; +import {filter} from 'rxjs/operators/filter'; +import {Subject} from 'rxjs/Subject'; +import {NgbTypeahead, NgbTypeaheadSelectItemEvent} from '@ng-bootstrap/ng-bootstrap'; +import {StoreService} from '@eg/core/store.service'; + +export interface TypeaheadEntry { + id: any; + label: string; + disabled?: boolean; +} + +@Component({ + selector: 'eg-typeahead', + templateUrl: './typeahead.component.html' +}) +export class TypeaheadComponent implements OnInit { + + selected: TypeaheadEntry; + click$: Subject; + entrylist: TypeaheadEntry[]; + + @ViewChild('instance') instance: NgbTypeahead; + + // Placeholder text for selector input + @Input() placeholder = ''; + + @Input() persistKey: string; // TODO + + // Display all entries when the user clicks in the text filter + // box regardless of any text that already exists there. + @Input() clickShowsAll = true; + + // Entry ID of the default entry to select (optional) + // onChange() is NOT fired when applying the default value + @Input() startId: any; + + @Input() set entries(el: TypeaheadEntry[]) { + this.entrylist = el; + } + + // Emitted when the org unit value is changed via the selector. + // Does not fire on initialOrg + @Output() onChange: EventEmitter; + + // Useful for massaging the match string prior to comparison + // Default version trims leading/trailing spaces + formatMatchString: (TypeaheadEntry) => string; + + constructor( + private store: StoreService, + ) { + this.entrylist = []; + this.click$ = new Subject(); + this.onChange = new EventEmitter(); + } + + ngOnInit() { + + if (this.startId) { + this.selected = this.entrylist.filter( + e => e.id === this.startId)[0]; + } + + this.formatMatchString = (result: TypeaheadEntry) => { + return result.label.trim(); + }; + } + + // Fired by the typeahead to inform us of a change. + // TODO: this does not fire when the value is cleared :( -- implement + // change detection on this.selected to look specifically for NULL. + selectorChanged(selEvent: NgbTypeaheadSelectItemEvent) { + this.onChange.emit(selEvent.item.id); + } + + filter = (text$: Observable): Observable => { + return text$.pipe( + debounceTime(200), + distinctUntilChanged(), + + merge( + // Inject a specifier indicating the source of the + // action is a user click instead of a text entry. + this.click$.pipe(filter(() => !this.instance.isPopupOpen())) + .pipe(map(nothing => { + if (this.clickShowsAll) { + return '_CLICK_'; + } else { + return nothing; + } + })) + ), + + map(term => { + + if (term === '' || term === '_CLICK_') { + // Click events display all visible entrylist + return this.entrylist; + } + + // Filter entrylist whose labels substring-match the + // text entered. + return this.entrylist.filter(entry => + entry.label.toLowerCase().indexOf(term.toLowerCase()) > -1 + ); + }) + ); + } +} + + diff --git a/Open-ILS/src/eg2/src/app/staff/common.module.ts b/Open-ILS/src/eg2/src/app/staff/common.module.ts index 2dfbb3cd8f..a22b4e0a4e 100644 --- a/Open-ILS/src/eg2/src/app/staff/common.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/common.module.ts @@ -1,6 +1,7 @@ import {NgModule, ModuleWithProviders} from '@angular/core'; import {EgCommonModule} from '@eg/common.module'; import {StaffBannerComponent} from './share/staff-banner.component'; +import {TypeaheadComponent} from '@eg/share/typeahead/typeahead.component'; import {OrgSelectComponent} from '@eg/share/org-select/org-select.component'; import {AccessKeyDirective} from '@eg/share/accesskey/accesskey.directive'; import {AccessKeyService} from '@eg/share/accesskey/accesskey.service'; @@ -20,6 +21,7 @@ import {DateSelectComponent} from '@eg/share/date-select/date-select.component'; @NgModule({ declarations: [ StaffBannerComponent, + TypeaheadComponent, OrgSelectComponent, AccessKeyDirective, AccessKeyInfoComponent, @@ -35,6 +37,7 @@ import {DateSelectComponent} from '@eg/share/date-select/date-select.component'; exports: [ EgCommonModule, StaffBannerComponent, + TypeaheadComponent, OrgSelectComponent, AccessKeyDirective, AccessKeyInfoComponent, diff --git a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html index 074389a420..e560abc897 100644 --- a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html +++ b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html @@ -30,16 +30,19 @@
- - - -
- - - -
+
+ + + +
+
+
+
+ Typeahead: +
+