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.

Ultimate RxJS

Example Code

( StackBlitz )

Progress Bar
import './style.css';
import { Observable, of, empty, fromEvent, from } from 'rxjs';
import {
delay,
switchMapTo,
concatAll,
count,
scan,
withLatestFrom,
share
} from 'rxjs/operators';
const requestOne = of('first').pipe(delay(500));
const requestTwo = of('second').pipe(delay(800));
const requestThree = of('third').pipe(delay(1100));
const requestFour = of('fourth').pipe(delay(1400));
const requestFive = of('fifth').pipe(delay(1700));
const loadButton = document.getElementById('load');
const progressBar = document.getElementById('progress');
const content = document.getElementById('data');
// update progress bar as requests complete
const updateProgress = progressRatio => {
console.log('Progress Ratio: ', progressRatio);
progressBar.style.width = 100 * progressRatio + '%';
if (progressRatio === 1) {
progressBar.className += ' finished';
} else {
progressBar.className = progressBar.className.replace(' finished', '');
}
};
// simple helper to log updates
const updateContent = newContent => {
content.innerHTML += newContent;
};
const displayData = data => {
updateContent(`<div class="content-item">${data}</div>`);
};
// simulate 5 separate requests that complete at variable length
const observables: Array<Observable<string>> = [
requestOne,
requestTwo,
requestThree,
requestFour,
requestFive
];
const array$ = from(observables);
const requests$ = array$.pipe(concatAll());
const clicks$ = fromEvent(loadButton, 'click');
const progress$ = clicks$.pipe(switchMapTo(requests$), share());
const count$ = array$.pipe(count());
const ratio$ = progress$.pipe(
scan(current => current + 1, 0),
withLatestFrom(count$, (current, count) => current / count)
);
clicks$.pipe(switchMapTo(ratio$)).subscribe(updateProgress);
progress$.subscribe(displayData);

html

<div class="progress-container">
<div class="progress" id="progress"></div>
</div>
<button id="load">
Load Data
</button>
<div id="data"></div>

Thanks to @johnlinquist for the additional help with example!

Operators Used