--- /dev/null
+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<string>;
+ 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<TypeaheadEntry>;
+
+ // 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<string>();
+ this.onChange = new EventEmitter<TypeaheadEntry>();
+ }
+
+ 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<string>): Observable<TypeaheadEntry[]> => {
+ 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
+ );
+ })
+ );
+ }
+}
+
+
import {Pager} from '@eg/share/util/pager';
import {DateSelectComponent} from '@eg/share/date-select/date-select.component';
import {PrintService} from '@eg/share/print/print.service';
+import {TypeaheadEntry} from '@eg/share/typeahead/typeahead.component';
@Component({
templateUrl: 'sandbox.component.html'
gridDataSource: GridDataSource = new GridDataSource();
+ taEntries: TypeaheadEntry[];
+
btSource: GridDataSource = new GridDataSource();
world = 'world'; // for local template version
btGridTestContext: any = {hello : this.world};
private strings: StringService,
private toast: ToastService,
private printer: PrintService
- ) {}
+ ) {
+
+ this.taEntries = [];
+ }
ngOnInit() {
{name: 'The Tick', state: 'TX'}
];
+ this.pcrud.retrieveAll('cmrcfld', {order_by:{cmrcfld: 'name'}})
+ .subscribe(format =>
+ this.taEntries.push({id: format.id(), label: format.name()}));
+
this.btSource.getRows = (pager: Pager, sort: any[]) => {
const orderBy: any = {cbt: 'name'};
return cbt;
}));
};
+
+
}
btGridRowClassCallback(row: any): string {