3

I'm using rxjs 5.0:

How can I set a timeout, on this buffer. So that it will clear the bufferCount (11) when no keyup events happen for 5 seconds?

var keys = Rx.Observable.fromEvent(document, 'keyup');
var buffered = keys.bufferCount(11,1);
buffered.subscribe(x => console.log(x));
Armeen Moon
  • 18,061
  • 35
  • 120
  • 233

3 Answers3

2

I have another (and probably easier to understand) solution using window and switchMap():

var keys = Rx.Observable.fromEvent(document.getElementById('myinput'), 'keyup')
  .map(event => event.keyCode)
  .share();

var buffered = keys
  .window(keys.debounceTime(5000))
  .switchMap(observable => observable.bufferCount(5, 1))
  .filter(buffer => buffer.length === 5);

buffered.subscribe(x => console.log(x));

See demo: https://jsbin.com/cakoru/17/edit?js,console,output

When you don't type for at least 5s the window() operator creates a new Observable that is subscribed internally in switchMap() and chained with a new .bufferCount() operator.

martin
  • 93,354
  • 25
  • 191
  • 226
1

You can append a timeoutWith, which could return a fresh buffered after a certain timeout (5seconds in your case).

const keys$ = Rx.Observable.fromEvent(document, "keyup")
  .map(ev => ev.keyCode|| ev.which); // this is just to have a readable output here in the SO-console
  
const buffered$ = keys$
  .bufferCount(3,1)  // replaced your 11 with 3 for easy demonstration
  .timeoutWith(2000, Rx.Observable.defer(() => { // replaced 5 with 2 seconds (easier to test here)
     console.log("New Buffer!");
     return buffered$;
  }));

buffered$.subscribe(console.log);
<script src="https://unpkg.com/rxjs/bundles/Rx.min.js"></script>

As an improvement, this could be even enhanced to only start the stream on the first stroke, otherwise we would have a constant timeout running (not critical, but could still be prevented).

const keys$ = Rx.Observable.fromEvent(document, "keyup")
  .map(ev => ev.keyCode|| ev.which); // this is just to have a readable output here in the SO-console

const buffered$ = keys$
  .take(1)
  .switchMap(firstKey => {
    console.log("New Buffer!");
    return keys$
     .startWith(firstKey)
     .bufferCount(3,1)  // replaced your 11 with 3 for easy demonstration
     .timeoutWith(2000, Rx.Observable.defer(() => buffered$)); // replaced 5 with 2 seconds (easier to test here)
  });

buffered$.subscribe(console.log);
<script src="https://unpkg.com/rxjs/bundles/Rx.min.js"></script>
olsn
  • 16,644
  • 6
  • 59
  • 65
0

Here's how I'd do it:

const keys$ = Rx.Observable.fromEvent(document, 'keyup').map(ev => ev.keyCode|| ev.which);

keys$
  .debounceTime(5000)
  .startWith({})
  .switchMap(x => keys$.bufferCount(11, 1))
  .subscribe(x => console.log(x));

Here we've got a stream that yields a value each time typing stops for five seconds (kicked off with a dummy value) that switchMaps into a bufferCount.

Matt Burnell
  • 2,646
  • 1
  • 22
  • 23