Angular Material Autocomplete with HTTP Lookup

In this demo, we will build an angular autocomplete component that gets autocomplete suggestions from a http service such as a REST API. The idea here is that, instead of using a static autocomplete list, we are going to pull autocomplete suggestions directly from our database. This is a neat feature to have especially if you are implementing a search function in your angular app.

Getting Started

First, I am going to assume that, you have some basic knowledge on both Angular and Angular 2 Material. If you are new to this, please check out the tutorials on Angular here and Angular 2 Material here.

In this demo, we will create a simple search for Github repositories. You enter the name of a repository and get the results. Then you can use the results  (list of repositories matching the name you entered) as a autocomplete options. Github API provides the option to retrieve results for unauthenticated users, you can learn more here.

Make sure you have imported all Angular Material Modules you need for your specific project. In this project we will be using MatAutocompleteModule, MatFormFieldModule and MatInputModule.

So, without further ado, let’s get into the code:

Github Lookup Service

We are going to create a service that will interact with the Github API. It will make HTTP calls to the API and return an observable of the search results. To make things easier, we will also create an interface – GithubResponse – that we can use to type cast our results we expect from github. Please checkout out the interface details here.

Let’s look at our service.

// github.service.ts
export class GithubService {
  constructor(private http: HttpClient) {}

  search(query: string): Observable<GithubResponse> {
    const url = 'https://api.github.com/search/repositories';
    return this.http
      .get<GithubResponse>(url, {
        observe: 'response',
        params: {
          q: query,
          sort: 'stars',
          order: 'desc'
        }
      })
      .pipe(
        map((res: Response) => {
          return res.body;
        })
      );
  }
}

It has a single method, that takes in the search query and returns the results. This is your normal service and doesn’t do anything special.

Autocomplete Component

In our component, we will need an observable Property – GithubAutoComplete$ – which we can subscribe to using async pipe, so that it can always have the latest values of our autocomplete options. So, we shall first subscribe to the autocomplete form control value changes, then use the value of the autocomplete form control as the query for our search method. And then we shall return the results to the GithubAutoComplete$ property of our component.

First, declare a GithubAutoComplete$ and our form control property – autoCompleteControl:

public githubAutoComplete$: Observable<Items> = null;
public autoCompleteControl = new FormControl();

Then, let’s create a lookup method that maps the results from github to an object we can use and catch errors.

lookup(value: string): Observable<Items> {
    return this.githubService.search(value.toLowerCase()).pipe(
      // map the item property of the github results as our return object
      map(results => results.items),
      // catch errors
      catchError(_ => {
        return of(null);
      })
    );
}

And then, on component initialization (ngOnInit Method), assign our GithubAutoComplete$ to the observable of the valueChanges of our input form control.

ngOnInit() {
    this.githubAutoComplete$ = this.autoCompleteControl.valueChanges.pipe(
      startWith(''),
      // delay emits
      debounceTime(300),
      // use switch map so as to cancel previous subscribed events, before creating new once
      switchMap(value => {
        if (value !== '') {
          // lookup from github
          return this.lookup(value);
        } else {
          // if no value is present, return null
          return of(null);
        }
      })
    );
  }

NB: Please read through the comments for further code clarification.

And finally, in our template, we use async pipe to subscribe to the GithubAutoComplete$ observable inside *ngFor as shown below.

<mat-form-field>
  <input [formControl]="autoCompleteControl" type="text" placeholder="Pick one" aria-label="Number" matInput [matAutocomplete]="auto">
    <mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
       <mat-option *ngFor="let item of githubAutoComplete$ | async; let index = index" [value]="item.name">
        {{ item.name | titlecase}}
    </mat-option>
  </mat-autocomplete>
</mat-form-field>

And that’s it, a working Angular 2 Material Autocomplete which works with a HTTP Service.

NB: Remember to implement OnInit interface on your component to run the ngOnInit method on component initialization.

Source Code and Demo

You can find a demo to tryout with here and the source code here.

Sign in off

Thank you for getting this far on this post, I hope this was helpful. If I missed anything or something was not clear, please tell me on the comment section below.

Here are some more topics on Angular:

  1. Lazy Loading Images in Angular 6
  2. Options for Deploying Angular Apps
  3. How to Build a Custom Form Control in Angular
  4. Top VSCode Extensions for Angular Developers
  5. Working with Environment Variables in Angular 6

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.