I know a little bit of BaconJS, but now I'm trying to learn RxJS by creating a "User is typing..." indicator. It's pretty simple, it can be explained in two simple rules:
- When the user is typing, the indicator should be immediately visible.
- When the user stops typing, the indicator should still be visible until 1 second after the user's last typing action.
I'm not sure if this is correct, but I have so far created two streams:
- One heartbeat stream that emits a
- One stream to capture the user typing events and emit a
1for every event.
Then I merge them together, and simply tap into the result. If it's a
1, then I show the indicator. If it's a
0, then I hide the indicator.
This is what that looks like:
const showTyping = () => $('.typing').text('User is typing...'); const showIdle = () => $('.typing').text(''); // 1 second heartbeats are mapped to 0 const heartbeat$ = Rx.Observable .interval(1000) .mapTo(0); // user typing events are mapped to 1 const input$ = Rx.Observable .fromEvent($('#input'), 'input') .mapTo(1); // we merge the streams together const state$ = heartbeat$ .merge(input$) .do(val => val === 0 ? showIdle() : showTyping()) .subscribe(console.log);
Here is a link to the JSBin:
There are several problems and questions I have with this implementation:
- Sometimes when the user is typing, a
0sneaks through, so the indicator flashes away for a split second before coming back on the next user keystroke.
- It's not guaranteed that the indicator will disappear 1 second after the user stops typing. It's only guaranteed that the indicator will disappear within 1 second (which is kind of the opposite of what we want).
- Is using a heartbeat stream the correct RxJS way to do this? I have a feeling it might not be.
I have a feeling that I am completely off-base with my implementation, I appreciate any help that you may be able to provide. Thanks.