I'm trying to create a typeahead that will call a service on keyup as the user types into an input box. My input is inside an *ngIf, so I'm using ViewChildren and subscribing to it's changes to get the input. The method I am calling does not return a value, so I'm unsure how to properly compose rxjs operators to do this.
This is my current solution:
private searchBoxPlaceholder: ElementRef;
@ViewChildren("searchbox", { read: ElementRef }) elementRefs: QueryList<ElementRef>;
public ngAfterViewInit(): any {
this.elementRefs.changes.subscribe(() => {
if (this.elementRefs.toArray().length) {
fromEvent(this.elementRefs.first.nativeElement, "keyup")
.pipe(
filter(Boolean),
debounceTime(2000),
distinctUntilChanged(),
tap(() => {
this.filterSearch(this.elementRefs.first.nativeElement.value);
})
)
.subscribe();
}
});
}
It works, but I feel like there is a better way to structure this without nesting subscribes. I'm also unsure if tap() is the best rxjs operator to use in this case. I've tried various combinations of switchMap, mergMap, concatMap, but since filterSearch does not return an Observable it's not working for me.
Something like this... untested :)
FromEvent
returns an Observable
so you can use this within a switchMap
and avoid the multiple subscribes. Also added takeUntil
and a filter for the array length
public ngAfterViewInit(): any {
this.elementRefs.changes.pipe(
filter(() => this.elementRefs.toArray().length > 0),
switchMap(() => {
return fromEvent(this.elementRefs.first.nativeElement, 'keyup')
.pipe(
filter(Boolean),
debounceTime(2000),
distinctUntilChanged(),
tap(() => {
this.filterSearch(this.elementRefs.first.nativeElement.value);
})
);
}),
takeUntil(this.onDestroy$)
).subscribe();
}