116 lines
2.4 KiB
TypeScript
116 lines
2.4 KiB
TypeScript
import {Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
|
|
import {SearchResult} from "../../api/SearchResult";
|
|
import {ISearchService} from "../../api/ISearchService";
|
|
|
|
@Component({
|
|
selector: 'app-search',
|
|
templateUrl: './search.component.html',
|
|
styleUrls: ['./search.component.less']
|
|
})
|
|
export class SearchComponent<T> implements OnInit {
|
|
|
|
private changedTimeout: number | undefined;
|
|
|
|
private initial_?: number;
|
|
|
|
@ViewChild('input')
|
|
input2?: ElementRef;
|
|
|
|
@ViewChild('input')
|
|
input?: HTMLInputElement;
|
|
|
|
@ViewChild('resultList')
|
|
resultList?: HTMLDivElement;
|
|
|
|
@Input()
|
|
searchService!: ISearchService;
|
|
|
|
@Input()
|
|
allowEmpty: boolean = true;
|
|
|
|
@Output()
|
|
valueChange: EventEmitter<number | null> = new EventEmitter<number | null>();
|
|
|
|
term: string = "";
|
|
|
|
results: SearchResult[] = [];
|
|
|
|
selected?: SearchResult;
|
|
|
|
searching: boolean = false;
|
|
|
|
cancelOnBlur: boolean = true;
|
|
|
|
@Input()
|
|
set initial(value: number | undefined) {
|
|
this.initial_ = value;
|
|
if (this.initial) {
|
|
this.searchService.searchById(this.initial, result => this.selected = result, _ => _);
|
|
} else {
|
|
this.selected = undefined;
|
|
}
|
|
}
|
|
|
|
get initial(): number {
|
|
return this.initial_;
|
|
}
|
|
|
|
constructor() {
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
}
|
|
|
|
changed(): void {
|
|
this.clearChangedTimeout();
|
|
this.changedTimeout = window.setTimeout(() => this.doSearch(), 400);
|
|
}
|
|
|
|
private clearChangedTimeout(): void {
|
|
if (this.changedTimeout) {
|
|
clearTimeout(this.changedTimeout);
|
|
this.changedTimeout = undefined;
|
|
}
|
|
}
|
|
|
|
start(): void {
|
|
this.term = this.selected?.title || "";
|
|
if (this.resultList && this.input) {
|
|
this.resultList.style.left = this.input.style.left;
|
|
}
|
|
this.searching = true;
|
|
setTimeout(() => this.input2?.nativeElement.focus(), 0);
|
|
this.doSearch();
|
|
}
|
|
|
|
doSearch(): void {
|
|
this.clearChangedTimeout();
|
|
if (!this.term) {
|
|
this.results = [];
|
|
} else {
|
|
this.searchService.search(this.term, results => this.results = results, _ => _);
|
|
}
|
|
}
|
|
|
|
blur() {
|
|
if (this.cancelOnBlur) {
|
|
this.cancelSearch();
|
|
}
|
|
}
|
|
|
|
cancelSearch(): void {
|
|
this.searching = false;
|
|
}
|
|
|
|
dontCancelOnBlur(): void {
|
|
this.cancelOnBlur = false;
|
|
}
|
|
|
|
select(result: SearchResult | undefined): void {
|
|
this.searching = false;
|
|
this.selected = result;
|
|
this.valueChange.emit(this.selected?.id);
|
|
}
|
|
|
|
}
|