Async Input with Angular & RXJS

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: