LiveLoveApp logo

Solution - Higher-order Function Operator

Solution

import { from, fromEvent, Observable } from 'rxjs';
import {
  debounceTime,
  map,
  mergeMap,
  sequenceEqual,
  take,
  window
} from 'rxjs/operators';

const PASSCODE = [1, 1, 1, 1];
const buttons = document.querySelectorAll('.btn');

const verifyPasscode = (passcode: number[], timeout = 1000) => (
  source: Observable<number>
): Observable<boolean> =>
  source.pipe(
    window(source.pipe(debounceTime(timeout))),
    mergeMap((value) =>
      from(value).pipe(take(passcode.length), sequenceEqual(from(passcode)))
    )
  );

fromEvent<MouseEvent>(buttons, 'click')
  .pipe(
    map((event: MouseEvent) => {
      const target = event.target as HTMLButtonElement;
      return parseInt(target.dataset.key!, 10);
    }),
    verifyPasscode(PASSCODE)
  )
  .subscribe({
    error: console.error,
    next: console.log,
    complete: () => console.log('complete')
  });

Let's review the solution code above:

  • We have defined a new verifyPasscode higher-order function that accepts the passcode and an optional timeout.
  • The function returns a function that accepts the source Observable and returns an Observable that emits boolean next notifications.
  • Using the source Observable we pipe to the window() operator. We provide the window() operator a windowBoundaries Observable. The window() operator will create a new Observable that contains the buffered values when the windowBoundaries Observable emits a next notification. The windowBoundaries Observable that we provide to the window() operator is our source Observable that we debounce for the specified timeout.
  • Similar to the previous exercise using the pipe() function, we then use the mergeMap() operator that receives the passcode array of numbers. Using the from() operator we create a new Observable that emits each number value in sequence and then completes. Within the pipe() of this new Observable we use the sequenceEqual() operator to compare the Observable against the known passcode Observable, which we also create using the from() operator.
  • Finally, we add the newly created verifyPasscode() operator the pipe() after the map() operator for the Observable that was created using the fromEvent() operator.