Async Input with Angular & RXJS
Let's create an async input using Angular and rxjs
First, let's see what the problem is
Imagine that you have an input in your web page to consult against a large database of names. When the user types in the input, we should show an autocomplete list according to the text provided by the user.
The question is, When should we send the request to the API to get the autocomplete data?
Well, one option is to send the request with every keystroke of the user. But, as frontend developers, we need to minimize the requests to the backend in order to keep the application optimized. So, what can we do?
Follow this article to find out the solution:
Creating the input
In the app.module.ts
let's add the ReactiveFormsModule
1import { NgModule } from '@angular/core'; 2import { BrowserModule } from '@angular/platform-browser'; 3import { ReactiveFormsModule } from '@angular/forms'; 4 5import { AppComponent } from './app.component'; 6 7@NgModule({ 8 declarations: [ 9 AppComponent 10 ], 11 imports: [ 12 BrowserModule, 13 ReactiveFormsModule 14 ], 15 providers: [], 16 bootstrap: [AppComponent] 17}) 18export class AppModule { } 19
Now, we can use the ReactiveForms features in our AppComponent
Next step, create the form control in app.component.ts
and
subscribe to valueChanges Observable
1import { Component, OnInit } from '@angular/core'; 2import { FormControl } from '@angular/forms'; 3 4@Component({ 5 selector: 'app-root', 6 templateUrl: './app.component.html', 7 styleUrls: ['./app.component.scss'] 8}) 9export class AppComponent implements OnInit { 10 bigInput: FormControl = new FormControl(''); 11 12 ngOnInit(): void { 13 this.bigInput.valueChanges.subscribe((value: string) => { 14 console.log('Value: ', value); 15 }); 16 } 17} 18
Finally, let's render the component
1<div class="container"> 2 <input 3 class="big-input" 4 placeholder="Type a text" 5 [formControl]="bigInput" 6 /> 7</div> 8
As you can see, we are using the formControl
attribute to reference the input with the
control created in the app.component.ts
file.
And when we type in the input, we can see the result on the console, something like this
a an and andr andre andres
Perfect, you just created a functional two-way bound data input.
Using rxjs operators
As we can see in the last picture, the user types "Andres". Then, we want to send the request to the backend when the user stops typing.
So, how do we know that the user has stopped typing? Well, it is here where rxjs
helps.
First, let's import two methods into our app.component.ts
file:
1import { debounceTime, distinctUntilChanged } from 'rxjs'; 2
-
debounceTime: This operator only emits the most recent emission after a delay time. We define the delay time. This operator is very useful because we only need the word 'andres'. We don't need 'a' or 'an' or 'and'.
-
distinctUntilChanged: This operator avoids getting repeated values between emissions. Hence, if we already requested data from 'andres' and the user deleted the 's' and immediately added the 's' again, we don't want to create the request again, right?.
Applying the operators
Now, these operators are going to be applied to the valueChanges
subscription. Like this:
1 this.bigInput.valueChanges 2 .pipe( 3 debounceTime(2000), 4 distinctUntilChanged() 5 ) 6 .subscribe((value: string) => { 7 console.log(value); 8 }); 9
As you can see, we are adding the pipe
method before the subscription to apply the rxjs operators.
Also, we are setting the debounceTime
with a time of 2000
, which means 2 seconds.
Eventually, if we try to fill the input again with the word 'andres' after 2 seconds, we will see in the console:
andres
a single log.
That's perfect. We just created an async input and now we can send the request to the backend.
Finally, in the subscribe, let's add some basic validation:
1ngOnInit(): void { 2 this.bigInput.valueChanges 3 .pipe( 4 debounceTime(2000), 5 distinctUntilChanged() 6 ) 7 .subscribe((value: string) => { 8 if(!value || value.trim() === ''){ 9 return; 10 } 11 // create fetch to backend in here 12 }); 13} 14
Summary
Well, that's all folks. We learn how to create an async input in Angular using subscription operators. You can find the repository with all this code implemented.
Please go to the 'contact' section if you have any input about this article. Happy Coding.
References: