Learn RxJS
Search…
Save Indicator
This recipe demonstrates the creation of a google docs-esque save indicator with RxJS.

Example Code

Could not load image
Save Indicator
1
import { fromEvent, of, merge, empty, concat, defer } from 'rxjs';
2
import {
3
delay,
4
map,
5
mergeMap,
6
tap,
7
debounceTime,
8
distinctUntilChanged,
9
mapTo,
10
filter,
11
share,
12
switchAll
13
} from 'rxjs/operators';
14
import { format } from 'date-fns';
15
16
// track in progress saves
17
let savesInProgress = 0;
18
19
// references
20
const input = document.getElementById('note-input');
21
const saveIndicator = document.querySelector('.save-indicator');
22
23
// streams
24
const keyup$ = fromEvent(input, 'keyup');
25
26
// fake save request
27
const saveChanges = value => {
28
return of(value).pipe(delay(1500));
29
};
30
31
/**
32
* Trigger a save when the user stops typing for 200ms
33
* After new data has been successfully saved, so a saved
34
* and last updated indicator.
35
*/
36
const inputToSave$ = keyup$.pipe(
37
debounceTime(200),
38
map(e => e.target.value),
39
distinctUntilChanged(),
40
share()
41
);
42
43
const savesInProgress$ = inputToSave$.pipe(
44
mapTo(of('Saving')),
45
tap(_ => savesInProgress++)
46
);
47
48
const savesCompleted$ = inputToSave$.pipe(
49
mergeMap(saveChanges),
50
tap(_ => savesInProgress--),
51
// ignore if additional saves are in progress
52
filter(_ => !savesInProgress),
53
mapTo(
54
concat(
55
// display saved for 2s
56
of('Saved!'),
57
empty().pipe(delay(2000)),
58
// then last updated time, defer for proper time
59
defer(() => of(`Last updated: ${format(Date.now(), 'MM/DD/YYYY hh:mm')}`))
60
)
61
)
62
);
63
64
merge(savesInProgress$, savesCompleted$)
65
.pipe(
66
/*
67
If new save comes in when our completion observable is running, we want to switch to it for a status update.
68
*/
69
switchAll()
70
)
71
.subscribe(status => {
72
saveIndicator.innerHTML = status;
73
});
Copied!
Last modified 1yr ago
Copy link
Contents
Example Code