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:
I'm not sure if this is correct, but I have so far created two streams:
0 every second.1 for 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:
http://jsbin.com/vekixuv/edit?js,console,output
There are several problems and questions I have with this implementation:
0 sneaks through, so the indicator flashes away for a split second before coming back on the next user keystroke.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.
You don't even need to use two Observables and use just one with debounceTime(). All the logic you tried to make is already present in debounceTime() operator:
const showTyping = () =>
$('.typing').text('User is typing...');
const showIdle = () =>
$('.typing').text('');
const input$ = Rx.Observable
.fromEvent($('#input'), 'input')
.do(() => showTyping())
.debounceTime(1000)
.subscribe(() => showIdle());
See live demo: http://jsbin.com/cixipa/6/edit?js,console,output
You don't need a heartbeat for this, just emit change-events whenever something happens/changes:
const showTyping = () =>
$('.typing').text('User is typing...');
const showIdle = () =>
$('.typing').text('');
// user typing events
const input$ = Rx.Observable
.fromEvent($('#input'), 'input');
// user stopped typing
const stoppedTypingAfter1s$ = input$
.switchMapTo(Rx.Observable.timer(1000));
// we merge the streams together
const state$ = Rx.Observable.merge(
input$.mapTo(1),
stoppedTypingAfter1s$.mapTo(0)
)
.startWith(0)
.do(val => val === 0 ? showIdle() : showTyping())
.subscribe(console.log);
See live here.
The switchMap, will discard any previouse 1s-timer whenever a new typing-event is emitted.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With