Learn RxJS
Search…
Progress Bar
By @barryrowe​
This recipe demonstrates the creation of an animated progress bar, simulating the management of multiple requests, and updating overall progress as each completes.
​​
​
​

Example Code

Progress Bar
1
import './style.css';
2
​
3
import { Observable, of, empty, fromEvent, from } from 'rxjs';
4
import {
5
delay,
6
switchMapTo,
7
concatAll,
8
count,
9
scan,
10
withLatestFrom,
11
share
12
} from 'rxjs/operators';
13
​
14
const requestOne = of('first').pipe(delay(500));
15
const requestTwo = of('second').pipe(delay(800));
16
const requestThree = of('third').pipe(delay(1100));
17
const requestFour = of('fourth').pipe(delay(1400));
18
const requestFive = of('fifth').pipe(delay(1700));
19
​
20
const loadButton = document.getElementById('load');
21
const progressBar = document.getElementById('progress');
22
const content = document.getElementById('data');
23
​
24
// update progress bar as requests complete
25
const updateProgress = progressRatio => {
26
console.log('Progress Ratio: ', progressRatio);
27
progressBar.style.width = 100 * progressRatio + '%';
28
if (progressRatio === 1) {
29
progressBar.className += ' finished';
30
} else {
31
progressBar.className = progressBar.className.replace(' finished', '');
32
}
33
};
34
// simple helper to log updates
35
const updateContent = newContent => {
36
content.innerHTML += newContent;
37
};
38
​
39
const displayData = data => {
40
updateContent(`<div class="content-item">${data}</div>`);
41
};
42
​
43
// simulate 5 separate requests that complete at variable length
44
const observables: Array<Observable<string>> = [
45
requestOne,
46
requestTwo,
47
requestThree,
48
requestFour,
49
requestFive
50
];
51
​
52
const array$ = from(observables);
53
const requests$ = array$.pipe(concatAll());
54
const clicks$ = fromEvent(loadButton, 'click');
55
​
56
const progress$ = clicks$.pipe(switchMapTo(requests$), share());
57
​
58
const count$ = array$.pipe(count());
59
​
60
const ratio$ = progress$.pipe(
61
scan(current => current + 1, 0),
62
withLatestFrom(count$, (current, count) => current / count)
63
);
64
​
65
clicks$.pipe(switchMapTo(ratio$)).subscribe(updateProgress);
66
​
67
progress$.subscribe(displayData);
Copied!

html

1
<div class="progress-container">
2
<div class="progress" id="progress"></div>
3
</div>
4
​
5
<button id="load">
6
Load Data
7
</button>
8
​
9
<div id="data"></div>
Copied!
Thanks to @johnlinquist for the additional help with example!

Operators Used