This recipe demonstrates the creation of an animated progress bar, simulating the management of multiple requests, and updating overall progress as each completes.
Copy 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);
Copy <div class="progress-container">
<div class="progress" id="progress"></div>
</div>
<button id="load">
Load Data
</button>
<div id="data"></div>