Swipe To Refresh

By adamlubek

This recipe demonstrates RxJS implementation of swipe to refresh functionality. Inspired by @BenLesh RxJs talks.

Example Code

( StackBlitz )

index.ts

// RxJS v6+
import { fromEvent, iif, of, pipe } from 'rxjs';
import {
  finalize,
  mergeMap,
  takeUntil,
  takeWhile,
  repeat,
  map,
  tap,
  exhaustMap,
  delay
} from 'rxjs/operators';

const setRefreshPos = y =>
  (document.getElementById('refresh').style.top = `${y}px`);
const resetRefresh = () => setRefreshPos(10);
const setData = data => (document.getElementById('data').innerText = data);

const fakeRequest = () =>
  of(new Date().toUTCString()).pipe(
    tap(_ => console.log('request')),
    delay(1000)
  );

const takeUntilMouseUpOrRefresh$ = pipe(
  takeUntil(fromEvent(document, 'mouseup')),
  takeWhile(y => y < 110)
);
const moveDot = y => of(y).pipe(tap(setRefreshPos));
const refresh$ = of({}).pipe(
  tap(resetRefresh),
  tap(e => setData('...refreshing...')),
  exhaustMap(_ => fakeRequest()),
  tap(setData)
);

fromEvent(document, 'mousedown')
  .pipe(
    mergeMap(_ => fromEvent(document, 'mousemove')),
    map((e: MouseEvent) => e.clientY),
    takeUntilMouseUpOrRefresh$,
    finalize(resetRefresh),
    exhaustMap(y => iif(() => y < 100, moveDot(y), refresh$)),
    finalize(() => console.log('end')),
    repeat()
  )
  .subscribe();

html

<style>
  #refresh {
    position: absolute;
    width: 20px;
    height: 20px;
    background: grey;
    border-radius: 50%;
    left: 50%;
  }

  #point {
    position: absolute;
    width: 10px;
    height: 10px;
    background: lightgrey;
    border-radius: 50%;
    left: 51%;
    top: 105px;
  }

  #data {
    position: absolute;
    top: 150px;
  }
</style>

<div id='refresh'></div>
<div id='point'></div>
<div id='data'>Swipe gray dot down to get latest date/time</div>

Operators Used

Last updated