Collect keyboard input over timespan

Viewed 143

I'm using Angular 10 and trying to collect window:keyup events for a certain amount of time using RXJS - but unfortunately not very successful at all. Basically I want to input data and if no key is pressed for a certain amount of time, the request should be submitted.

fromEvent(window, 'keyup').pipe(
  map((ev: KeyboardEvent) => ev.key),
  scan((acc, value) => acc + value),
  debounceTime(500)
).subscribe(key => {
  console.log(key);
});

That's how my basic approach looks like, which is basically doing what I want, but I'm unable to delete the scan result within the subscription result.

Is there a better way to achieve my desired behavior?

1 Answers

One approach I have found is to use a Subject alongside, and have it emit the results of an Observable which sets itself up and destroys itself for each produced string:

const result$ = new Subject<string>();

fromEvent(window, 'keyup').pipe(
  exhaustMap(key => fromEvent(window, 'keyup').pipe(
    takeUntil(result$),
    startWith(key),
    map((event: KeyboardEvent) => event.key),
    scan((acc, curr) => acc + curr),
    debounceTime(500),
    tap(val => result$.next(val)),
  )),
).subscribe();

result$.subscribe(console.log); // here you would do your request logic, 
                                // and make sure to set it to unsubscribe 
                                // (with a takeUntil and a destroy$ Subject, for example).

When a first key is pressed, it sets up the outer Observable. It then creates the inner Observable, watching every key pressed until the debounce time of 500ms passes, at which point it causes the Subject to emit. The emission of that very same Subject then kills the inner Observable, allowing the outer Observable to start up again. Don't forget to use an unsubscription method on BOTH the Subject and the outer Observable.

Related