Currently, I am utilizing ng-select for a form that allows users to search for activities to add. The ng-select component triggers a function whenever something is typed into the field. This function then calls a service that fetches an array of activities whose names match the input. Subsequently, the ng-select component subscribes to this observable via async.
The main issue I am encountering is that it appears the ng-select is having trouble accessing or subscribing to the Observable. To resolve this, I had to introduce a delay to the Observable returned by the service.
Snippet from HTML:
<label for="class">Activity</label>
<ng-select [items]="activities$ | async"
groupBy="type"
[(ngModel)]="selectedActivity"
[ngModelOptions]="{standalone: true}"
(search)="inputChanged($event)">
</ng-select>
Corresponding TypeScript code:
activities$!: Observable<Activity[]>;
selectedActivity!: Activity;
private modelChanged: Subject<string> = new Subject<string>();
private searchSubscription!: Subscription;
debounceTime = 500;
constructor(private dataService: DataService) { }
ngOnInit(): void {
this.initActivitySearchListener();
};
initActivitySearchListener(): void {
this.searchSubscription = this.modelChanged
.pipe(
debounceTime(this.debounceTime),
)
.subscribe(input => {
console.log(input)
this.updateSearch(input);
});
}
//Function triggered when typing in activity search bar
inputChanged($event: any) {
this.modelChanged.next($event.term);
}
updateSearch(term: string) {
console.log(term);
this.activities$ = this.dataService.getActivitiesForList(term);
this.dataService.getActivitiesForList(term).subscribe(data => console.log(data));
}
Data fetching Service:
getActivitiesForList(inputString: string): Observable<Activity[]> {
let parsedResult: Activity[] = [];
this.http.get<any>(this.HOST + this.API_URI + 'activity?searchText=' + inputString).subscribe((data) => {
for (const activity of data) {
switch (activity.type) {
case "dungeon":
let tempBossArray: any[] = [];
activity.dungeon_boss.forEach((bossObject: any) => {
tempBossArray.push(bossObject.name);
});
parsedResult.push({ id: activity.id, name: activity.name + ' (' + tempBossArray.toString() + ') ' + '[Level ' + activity.level + ']', type: "Dungeon" });
break;
case "quest":
parsedResult.push({ id: activity.id, name: activity.name + ' (' + activity.category + ')', type: "Quest" });
break;
default:
break;
}
}
});
return of(parsedResult).pipe(delay(100));
};
If you notice on the last line, there's pipe(delay(100))
. If removed, my ng-select won't display any data even though the array is being fetched, as verified through console.log()