Learn RxJS
Search…
Stop Watch
By adamlubek
This recipe demonstrates RxJS implementation of Stop Watch, inspired by RxJS Advanced Patterns – Operate Heavily Dynamic UI’s talk by @Michael_Hladky

Example Code

Stop Watch

index.ts

1
// RxJS v6+
2
import { fromEvent, interval, merge, noop, NEVER } from 'rxjs';
3
import { map, mapTo, scan, startWith, switchMap, tap } from 'rxjs/operators';
4
5
interface State {
6
count: boolean;
7
countup: boolean;
8
speed: number;
9
value: number;
10
increase: number;
11
}
12
13
const getElem = (id: string): HTMLElement => document.getElementById(id);
14
const getVal = (id: string): number => parseInt(getElem(id)['value']);
15
const fromClick = (id: string) => fromEvent(getElem(id), 'click');
16
const fromClickAndMapTo = (id: string, obj: {}) =>
17
fromClick(id).pipe(mapTo(obj));
18
const fromClickAndMap = (id: string, fn: _ => {}) =>
19
fromClick(id).pipe(map(fn));
20
const setValue = (val: number) =>
21
(getElem('counter').innerText = val.toString());
22
23
const events$ = merge(
24
fromClickAndMapTo('start', { count: true }),
25
fromClickAndMapTo('pause', { count: false }),
26
fromClickAndMapTo('reset', { value: 0 }),
27
fromClickAndMapTo('countup', { countup: true }),
28
fromClickAndMapTo('countdown', { countup: false }),
29
fromClickAndMap('setto', _ => ({ value: getVal('value') })),
30
fromClickAndMap('setspeed', _ => ({ speed: getVal('speed') })),
31
fromClickAndMap('setincrease', _ => ({ increase: getVal('increase') }))
32
);
33
34
const stopWatch$ = events$.pipe(
35
startWith({
36
count: false,
37
speed: 1000,
38
value: 0,
39
countup: true,
40
increase: 1
41
}),
42
scan((state: State, curr): State => ({ ...state, ...curr }), {}),
43
tap((state: State) => setValue(state.value)),
44
switchMap((state: State) =>
45
state.count
46
? interval(state.speed).pipe(
47
tap(
48
_ =>
49
(state.value += state.countup ? state.increase : -state.increase)
50
),
51
tap(_ => setValue(state.value))
52
)
53
: NEVER
54
)
55
);
56
57
stopWatch$.subscribe();
Copied!

index.html

1
<style>
2
input,
3
#counter,
4
#controls {
5
text-align: center;
6
margin: auto;
7
}
8
9
#counter {
10
font-size: 50px;
11
}
12
13
#controls {
14
width: 50%;
15
}
16
</style>
17
18
<div id="counter">0</div>
19
<div id="controls">
20
<fieldset>
21
<legend>Setup</legend>
22
<button id="start">start</button>
23
<button id="pause">pause</button>
24
<button id="reset">reset</button>
25
</fieldset>
26
<fieldset>
27
<legend>Count</legend>
28
<button id="countup">count up</button>
29
<button id="countdown">count down</button>
30
</fieldset>
31
<fieldset>
32
<legend>Set to</legend>
33
<input id="value" value="0"></input>
34
<br/>
35
<button id="setto">set value</button>
36
</fieldset>
37
<fieldset>
38
<legend>Speed</legend>
39
<input id="speed" value="1000"></input>
40
<br/>
41
<button id="setspeed">set speed</button>
42
</fieldset>
43
<fieldset>
44
<legend>Increase</legend>
45
<input id="increase" value="1"></input>
46
<br/>
47
<button id="setincrease">set increase</button>
48
</fieldset>
49
</div>
Copied!

Operators Used

Last modified 1yr ago