Practical Implementation of RxJS switchMap in Angular Typeahead

If you’re like me, you want to learn new concepts with a simple practical example. When I was trying to learn the RxJS switchMap operator, I struggled a bit to grasp the concept based on the official definition:

rxjs.dev

If you are in doubt about the definition, here are the most important points:

  • We have nested Observables (outer and inner)
  • switchMap is used to “flatten” the two Observable streams into one big stream
  • switchMap only returns the LATEST emitted value from the big stream
  • All previous values get dropped

It’s like a zipper on your coat: two sides being joined into one.

Let’s see this in action with a use case.

Use Case: Typeahead

A typeahead is a smart search bar that gives predetermined suggestions based on what you are typing. So if you type “A”, you will only see a list of results containing the letter “A”.

Here is the Angular code:

app.component.ts

import { Component, OnInit } from '@angular/core';
import { fromEvent, of } from 'rxjs';
import { map, switchMap, tap } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  template: `
    <br/>
    <input id='type-ahead'/>
    <br/>
    <div id='output'></div>
  `,
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {

  ngOnInit() {
    // Watch user keyboard input
    this.typeahead();
  }

  // Observable of filtered search results
  public fetchData = keys => of(this.filterData(keys));

  // Compare user input to available list, filter results
  private filterData(keys) {
    if (keys.length) {
      return [
        'argue',
        'attest',
        'authenticate',
        'bear',
        'certify',
        'confirm',
      ].filter(option => option.includes(keys))
    } else {
      return []
    }
  }

  public typeahead() {
   // outer Observable: Watch user input
    fromEvent(document.getElementById('type-ahead'), 'keyup')
      .pipe(
        // Extract text typed by user
        map((e: any) => e.target.value),
        // Stabilize user input
        debounceTime(100)
        // Inner Observable: Take latest emitted input, ignore old input
        switchMap(this.fetchData),
        // Display result in HTML
        tap(c => document.getElementById('output').innerText = c.join('\n'))
      ).subscribe();
  }
}

We have two Observables: the outer fromEvent and the inner fetchData. The switchMap gives us the useful ability to only look at the latest value from the combined streams of these two Observables that have been “zipped” together.

So there you have it! A useful implementation of the RxJS switchMap operator.

Latest Posts

Leave a comment