In this post I will demonstrate a general strategy for performing a search or other API call while a user is typing, by making an input field for a unique username.
I like this strategy because it is straight-forward, adaptable to any framework, and extendable to other use-cases where you might need to show immediate feedback to a user based on an action.
First, create a BehaviorSubject of type string to record the user's actions, and use the asObservable()
method on it to create a variable that will update with each key-press.
// Search
inputActionSubject = new BehaviorSubject<string>('');
inputAction$ = this.inputActionSubject.asObservable();
onUserInput(event: Event): void {
const input = (event?.target as HTMLInputElement)?.value;
this.inputActionSubject.next(input);
}
<input
matInput
[formControl]="inputControl"
(input)="onUserInput($event)"
#input />
Apply the following rxjs operators to call the API each time the variable updates.
-
debounceTime()
Wait this many milliseconds before proceeding to avoid sending requests while the user is still typing -
switchMap()
Call the API with the input as a parameter, and unsubscribe from the previous call, since we're sending a new one -
tap()
Connect to the observable returned by the API call within the observable for the user-input
// On Initialization this.inputAction$ .pipe( debounceTime(300), switchMap((input: string) => this.userService.getUsersByUsername(input).pipe( tap((res: User[]) => { this.checkForDuplicateUsername(res); }) ) ) ) .subscribe();
Process the results from the API call and provide feedback to the user. In our case: set an error on the FormControl
if the list of users with the given username is not empty.
// Using Angular Reactive Forms
@ViewChild('input') input: ElementRef<HTMLInputElement>;
inputControl = new FormControl('', [
Validators.required,
Validators.minLength(3),
]);
checkForDuplicateUsername(users: User[]): void {
if (users.length) {
this.inputControl.setErrors({ notUnique: true });
this.input.nativeElement.blur(); // Trigger update
this.input.nativeElement.focus();
}
}
Full Angular Implementation
Top comments (3)
A way to make it fail-safe: blog.strongbrew.io/building-a-safe...
Very cool solution
I'm glad you like it! This is auto-complete component is where I picked it up from: dev.to/anirbmuk/auto-complete-with...