DEV Community

Michael
Michael

Posted on • Updated on

Using rxjs Operators to Create a Unique Username Field

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.

Image description

Image description

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);
  }
Enter fullscreen mode Exit fullscreen mode
   <input   
     matInput
     [formControl]="inputControl"
     (input)="onUserInput($event)"
     #input />
Enter fullscreen mode Exit fullscreen mode

 
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();
     }
   }
Enter fullscreen mode Exit fullscreen mode

 

Full Angular Implementation

Top comments (3)

Collapse
 
mikewestdev profile image
Michael

A way to make it fail-safe: blog.strongbrew.io/building-a-safe...

Collapse
 
jk6 profile image
Jason Kelly

Very cool solution

Collapse
 
mikewestdev profile image
Michael

I'm glad you like it! This is auto-complete component is where I picked it up from: dev.to/anirbmuk/auto-complete-with...