In the Angular Material tutorial, we’re going to discuss how to create a Material Autocomplete showing suggestion results from a remote server by using the mat-autocomplete component in the Angular 10/9/8/7/6/5/4 application.
We have already discussed the basic usage and implementation of Angular Material Autocomplete Component in an Angular Application in our previous post here.
Autocomplete is a very popular behaviour used in many applications to ease user form filling experience by providing some already built strings to fast data entry. Autocomplete is very similar to Input fields with addition to some Items showing up when the user focuses on that Input.
Sometimes we may need to show some results from the server-side as per a request made by the user. For example, there are two fields for State and City. A user will first select a State, then City list will load in other Input from the server-side according to state selected, as we may have thousands of cities from 12-15 states Right?
In this post, we will add Angular Autocomplete with the Debounce feature which will fetch results from server/API response. Here we will also use the HttpClient service of Angular to make a Get request to IMDB movies API for demonstration.
You can check my previous post to know more about adding Angular Material to the Angular project.
Autocomplete with server-side responses will also use the debounceTime
method of Rxjs for optimized API calls for results.
Implement Server Side Autocomplete
Let’s add HttpClientModule
and some other Angular material Modules which will be used in our demo.
Open App’s main module file app.module.ts then replace the below code.
//app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatInputModule } from '@angular/material/input';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
FormsModule,
ReactiveFormsModule,
MatInputModule,
MatAutocompleteModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
To make server HTTP calls add HttpClientModule
, for autocomplete import MatInputModule
& MatAutocompleteModule
.
We have FormsModule
with ReactiveFormsModule
so that we can easily bind RxJS debounceTime
and also get the input value.
Add Autocomplete template
In app.component.html file replace below template to show Input Field with Autocomplete.
<div>
<mat-form-field>
<input matInput placeholder="Search" aria-label="State" [matAutocomplete]="auto" [formControl]="searchMoviesCtrl">
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngIf="isLoading" class="is-loading">Loading...</mat-option>
<ng-container *ngIf="!isLoading">
<mat-option *ngFor="let movie of filteredMovies" [value]="movie.Title">
<span><b>{{movie.Title}}</b> ({{movie.Year}})</span>
</mat-option>
</ng-container>
</mat-autocomplete>
</mat-form-field>
<br>
<ng-container *ngIf="errorMsg; else elseTemplate">
{{errorMsg}}
</ng-container>
<ng-template #elseTemplate>
<h5>Selected Value: {{searchMoviesCtrl.value}}</h5>
</ng-template>
</div>
In app.component.ts file replace following code to make server calls to populate Autocomplete results using OMDB free API.
//app.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { debounceTime, tap, switchMap, finalize } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
searchMoviesCtrl = new FormControl();
filteredMovies: any;
isLoading = false;
errorMsg: string;
constructor(
private http: HttpClient
) { }
ngOnInit() {
this.searchMoviesCtrl.valueChanges
.pipe(
debounceTime(500),
tap(() => {
this.errorMsg = "";
this.filteredMovies = [];
this.isLoading = true;
}),
switchMap(value => this.http.get("http://www.omdbapi.com/?apikey=[YOUR_KEY_HERE]=" + value)
.pipe(
finalize(() => {
this.isLoading = false
}),
)
)
)
.subscribe(data => {
if (data['Search'] == undefined) {
this.errorMsg = data['Error'];
this.filteredMovies = [];
} else {
this.errorMsg = "";
this.filteredMovies = data['Search'];
}
console.log(this.filteredMovies);
});
}
}
The debounceTime
checks if the keypress interval is less than the time provided, then cancels the further events.
The tap
and finalize
operators are used to handling events before the server call and after response.
The switchMap
is most similar to mergeMap
but it is used here as it cancels the previous request event if the response is not received yet. But mergeMap waits for a previous response then make the next call so this behaviour is not required here.
Check Updated for Angular Material 12 Autocomplete with HTTP API Remote Search Results
Also check: How to add Angular Material Loaders and Spinners in Angular App
That’s it now you have a working Angular Material Autocomplete fetching server-side responses as user types in having RxJS DebounceTime which will only hit API HTTP call when the user stops typing.
NIce work!! I tried this but kept getting ORS Error
This tutorial is exactly what I was looking for but the api url needs to be updated to accept the search parameter so you can see the results that get returned, as is it will fail and not work.
Here is the code that worked for me:
switchMap(value => this.http.get(“http://www.omdbapi.com/?s=” + value +“&apikey=YOURAPIKEY”)
Thanks for this tutorial, it was very useful!