121 lines
3.8 KiB
TypeScript
121 lines
3.8 KiB
TypeScript
import { Input, OnInit, Component, Output, EventEmitter, ViewChild, ElementRef, QueryList, AfterViewInit } from '@angular/core';
|
|
import { FormControl, FormGroupDirective, NgForm, FormArray, AbstractControl, FormGroup, FormBuilder, Validators } from '@angular/forms';
|
|
import { ErrorStateMatcher, MatChipInputEvent, MatAutocompleteSelectedEvent, MatChipList } from '@angular/material';
|
|
import { TranslateService } from '@ngx-translate/core';
|
|
import { Subject , Observable } from 'rxjs';
|
|
import { map, startWith, merge, mapTo, mergeMap, timeout } from 'rxjs/operators';
|
|
import { SingleAutoCompleteConfiguration } from './single-auto-complete-configuration';
|
|
|
|
@Component({
|
|
selector: 'app-single-auto-complete',
|
|
templateUrl: './single-auto-complete.component.html',
|
|
styleUrls: ['./single-auto-complete.component.scss']
|
|
})
|
|
export class SingleAutoCompleteComponent implements OnInit {
|
|
|
|
@Input() reactiveFormControl: FormControl;
|
|
@Input() placeholder: string;
|
|
@Input() validationErrorString: string;
|
|
|
|
@Input() configuration: SingleAutoCompleteConfiguration;
|
|
|
|
// Selected Option Event
|
|
@Output() optionSelected: EventEmitter<any> = new EventEmitter();
|
|
|
|
private requestDelay = 200; //ms
|
|
private minFilteringChars = 3;
|
|
private loadDataOnStart = true;
|
|
|
|
// @Input() items: Observable<any[]>;
|
|
// @Input() filterFn?: (searchQuery: string) => Observable<any[]>;
|
|
// @Input() displayFn?: (item: any) => string;
|
|
// @Input() titleFn?: (item: any) => string;
|
|
// @Input() subtitleFn?: (item: any) => string;
|
|
loading = false;
|
|
_items: Observable<any[]>;
|
|
|
|
constructor() {
|
|
}
|
|
|
|
ngOnInit() {
|
|
|
|
}
|
|
|
|
filter(query: string): Observable<any[]> {
|
|
// If loadDataOnStart is enabled and query is empty we return the initial items.
|
|
if (this.isNullOrEmpty(query) && this.loadDataOnStart) {
|
|
return this.configuration.items || Observable.of([]);
|
|
} else if (query && query.length >= this.minFilteringChars) {
|
|
if (this.configuration.filterFn) {
|
|
return this.configuration.filterFn(query);
|
|
} else {
|
|
return this.configuration.items || Observable.of([]);
|
|
}
|
|
} else {
|
|
return Observable.of([]);
|
|
}
|
|
}
|
|
|
|
isNullOrEmpty(query: string): boolean {
|
|
return typeof query !== 'string' || query === null || query.length === 0;
|
|
}
|
|
|
|
_displayFn(item: any): string {
|
|
if (this.configuration.displayFn && item) { return this.configuration.displayFn(item); }
|
|
return item;
|
|
}
|
|
|
|
_titleFn(item: any): string {
|
|
if (this.configuration.titleFn && item) { return this.configuration.titleFn(item); }
|
|
return item;
|
|
}
|
|
|
|
_subtitleFn(item: any): string {
|
|
if (this.configuration.subtitleFn && item) { return this.configuration.subtitleFn(item); }
|
|
return null;
|
|
}
|
|
|
|
_requestDelay(): number {
|
|
return this.configuration.requestDelay || this.requestDelay;
|
|
}
|
|
|
|
_minFilteringChars(): number {
|
|
return this.configuration.minFilteringChars || this.minFilteringChars;
|
|
}
|
|
|
|
_loadDataOnStart(): boolean {
|
|
return this.configuration.loadDataOnStart || this.loadDataOnStart;
|
|
}
|
|
|
|
_optionSelected(event: MatAutocompleteSelectedEvent) {
|
|
this.optionSelected.emit(event.option.value);
|
|
}
|
|
|
|
_onInputFocus() {
|
|
// We set the items observable on focus to avoid the request being executed on component load.
|
|
if (!this._items) {
|
|
this._items = this.reactiveFormControl.valueChanges
|
|
.startWith(null)
|
|
.debounceTime(this.requestDelay)
|
|
.distinctUntilChanged()
|
|
.do(() => { this.loading = true; })
|
|
.flatMap(query => {
|
|
// If its a valid object, a selection just made and the object is set as the value of the form control. That means we should fire an extra request to the server.
|
|
if (this._isValidObject(query)) { return Observable.of([]); }
|
|
return this.filter(query);
|
|
})
|
|
.do(() => { this.loading = false; });
|
|
}
|
|
}
|
|
|
|
_isValidObject(value: any): boolean {
|
|
try {
|
|
if (!value) { return false; }
|
|
if (typeof value !== 'object') { JSON.parse(value); }
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|