I have a simple component that allows users to search using the values typed into a search box. I've come across two different ways to implement this functionality and both seem to work well.
Method 1 utilizes fromEvent
from RxJS to create an observable that captures changes in the input field value by referencing the input element with @ViewChild
.
On the other hand, Method 2 captures input field value changes using the keyup
event and then passes the new value to an RxJS Subject
.
Most of the examples I found on Stackoverflow and other websites favor the use of @ViewChild in scenarios like this. Are there specific reasons to choose one method over the other, or is it simply a matter of personal preference?
METHOD 1
app.component.html
<input type="text" #search placeholder="Search" />
<li *ngFor="let state of states$ | async">
{{ state.text }}
</li>
app.component.ts
export class AppComponent implements OnInit {
@ViewChild('search', { static: true }) search: ElementRef;
states$: Observable<any[]>;
constructor(private dataService: DataService) {}
ngOnInit(): void {
this.states$ = fromEvent(this.search.nativeElement, 'input').pipe(
map((event: any) => event.target.value),
debounceTime(500),
distinctUntilChanged(),
switchMap((searchText: string) => this.dataService.getData(searchText))
);
}
}
METHOD 2
app.component.html
<input
type="text"
(keyup)="searchStringChange(getValue($event))"
placeholder="Search"
/>
<li *ngFor="let state of states$ | async">
{{ state.text }}
</li>
app.component.ts
export class AppComponent implements OnInit {
states$: Observable<any[]>;
private searchText$ = new Subject<string>();
constructor(private dataService: DataService) {}
ngOnInit(): void {
this.states$ = this.searchText$.pipe(
debounceTime(500),
distinctUntilChanged(),
tap({ next: (searchText: string) => console.log(searchText) }),
switchMap((searchText: string) => this.dataService.getData(searchText))
);
}
searchStringChange(userInput: string) {
this.searchText$.next(userInput);
}
getValue(event: Event): string {
return (event.target as HTMLInputElement).value;
}
}