Я использую ngbtypeahead в качестве опции поиска автозаполнения, пользователь что-то вводит, это типизированное значение отправляется родительскому компоненту, который затем вызывает сервер, возвращаемое значение (Observable) затем передается обратно в ребенок.
я пытаюсь сделать только с switchMap
(конец моей трубы), как только мой typeAhead
компонент получает data
как @input
от родительского компонента (результаты отображаются как опции автозаполнения), data
- это результат звонка на сервер. Изначально (до того, как что-либо было введено) data
имеет значение NULL, и поэтому компонент typeAhead
имеет неопределенное значение для data
.
Моя проблема в том, что первый первый раз, когда я набираю то, что, кажется, происходит, заключается в том, что pipe
завершается раньше, чем data
был получен компонентом typeAhead (дочерний), это приводит к тому, что он отображает нет опции автозаполнения. Мой код приведен ниже, основной вопрос, который у меня возникает, заключается в том, что не так с моей функцией handleTypeahead
, которая не выдает введенные значения при вводе в автозаполнение.
import {ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, OnInit, Output} from '@angular/core';
import {Observable, of} from "rxjs";
import {
debounceTime,
delayWhen,
distinctUntilChanged, filter,
last,
map,
mergeMap,
switchMap,
tap,
withLatestFrom,
} from "rxjs/operators";
import {FilterService} from "@carebox/core";
import {ISearchCriteria} from "@carebox/core";
import {NgbTypeaheadSelectItemEvent} from "@ng-bootstrap/ng-bootstrap";
@Component({
selector: 'core-ui-typeahead-filter',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './typeahead-filter.component.html',
})
export class TypeaheadFilterComponent implements OnInit {
@Input() id: string;
@Input() name: string;
@Input() caption: string;
@Input() placeholder: string;
@Input() cssClass: string;
@Input() cssStyle: string;
@Input() function: any;
@Input() data: Observable<string[]>
model: any;
@Output() onTypeahead: EventEmitter<any> = new EventEmitter<any>();
@Output() onSelect: EventEmitter<any> = new EventEmitter<any>();
constructor() {
}
handleTypeahead = (text$: Observable<string>) => {
this.data.subscribe(
(data) => {
if (data) {
return text$.pipe(
distinctUntilChanged(),
debounceTime(200),
filter(term => term !== ''),
tap((term) => console.log("handleTypeahead", term)),
tap((term) => this.onTypeahead.emit(term)),
/*map((term: string) => [])*/
/*map((term: string) => term === '' ? [] : this.data)*/
// withLatestFrom(this.data),
switchMap(() => this.data)
);
}
}
)
}
handleSelectItem(item) {
this.onSelect.emit(item);
}
ngOnInit() {
// this.data.subscribe()
}
}
Соответствующий шаблон:
<div class="form-group">
<label class="label-filters" for="{{id}}">
{{caption}}
</label>
<input id="{{id}}"
name="{{name}}"
type="text"
placeholder="{{placeholder}}"
class="{{cssClass}}"
style="{{cssStyle}}"
autocomplete="off"
[(ngModel)]="model"
[ngbTypeahead]="handleTypeahead"
(selectItem)="handleSelectItem($event.item)"
>
</div>
Одно решение, которое я попробовал, - просто добавить оператор delay
с задержкой 500 мс, это работает, но не элегантно и имеет некоторые другие проблемы. Должен быть способ явно ожидать поступления значения @input.
Добавление соответствующего кода в родительский компонент, а также в шаблон:
/* NctId Filter */
public NctIdTypeahead(term: string) {
this.model.NctIdList = [];
if (!(term && term.length > 0)) {
return;
}
this.searchCriteria.nctIdPrefix = term;
this.searchCriteria.aggregateOn = 'nctid';
this.filterService.GetNctIdFilterData(this.searchCriteria).pipe(
last(),
map((result: any) => {
return result.nctid;
})
).subscribe(id => this.NctIdList = of(id))
}
А также шаблон (родительского):
<div class="col-sm-6 col-md-4 col-lg-3">
<core-ui-typeahead-filter
id="NctIdFilter"
caption="NCT ID"
placeholder="Type to select NCT ID"
i18n-placeholder="@@T-trials.trial_protocol_id_filter_placeholder"
[data]="NctIdList"
[cssClass]="'form-control'"
(onTypeahead)="NctIdTypeahead($event)"
(onSelect)="NctIdSelect($event)">
</core-ui-typeahead-filter>
</div>