Skip to content

Instantly share code, notes, and snippets.

@ccnokes
Last active October 11, 2022 14:18
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ccnokes/bd5b975dab213bb60b877e49754dd675 to your computer and use it in GitHub Desktop.
Save ccnokes/bd5b975dab213bb60b877e49754dd675 to your computer and use it in GitHub Desktop.
Online/offline event observable with RxJS (see comments below for a better, more up-to-date way of doing this)
const { Observable } = require('rxjs/Observable');
require('rxjs/add/observable/fromEvent');
require('rxjs/add/operator/map');
require('rxjs/add/observable/merge');
function createOnline$() {
//merge several events into one
return Observable.merge(
//use .map() to transform the returned Event type into a true/false value
Observable.fromEvent(window, 'offline').map(() => false),
Observable.fromEvent(window, 'online').map(() => true),
//start the stream with the current online status
Observable.create(sub => {
sub.next(navigator.onLine);
sub.complete(); //this one only emits once, so now we end it
})
);
}
// implement it
const onlineSub = createOnline$().subscribe(isOnline => console.log(isOnline));
onlineSub.unsubscribe();
@plevold
Copy link

plevold commented Jun 3, 2018

Thanks for the Gist! This was exactly what I was looking for. As of RxJS 6.0 the syntax seems to have changed slightly though. I modified it as shown below and it seems to work fine for me.

import { Observable, fromEvent, merge} from 'rxjs';
import { map } from 'rxjs/operators';

function createOnline$() {
  return merge(
    fromEvent(window, 'offline').pipe(map(() => false)),
    fromEvent(window, 'online').pipe(map(() => true)),
    Observable.create(sub => {
      sub.next(navigator.onLine);
      sub.complete();
    }));
  }

@thecyberd3m0n
Copy link

could you write unit test for this?

@dfsq
Copy link

dfsq commented Aug 24, 2018

I think you could also use of(navigator.onLine) for initial status event.

merge(
  fromEvent(window, 'offline').pipe(mapTo(false)),
  fromEvent(window, 'online').pipe(mapTo(true)),
  of(navigator.onLine),
);

@ccnokes
Copy link
Author

ccnokes commented Aug 5, 2019

I never saw any of these comments, sorry 😬.

@plevold Nice, thanks! I haven't kept up with RxJS so I appreciate that 👍

@vmasek
Copy link

vmasek commented Nov 8, 2019

combineLatest([
  fromEvent(window, 'online').pipe(startWith(null)),
  fromEvent(window, 'offline').pipe(startWith(null)),
]).pipe(
  map(() => navigator.onLine),
  shareReplay(),
);

@cmalard
Copy link

cmalard commented Feb 28, 2020

Lightest version, that always return navigator.onLine value:

merge(
  of(null),
  fromEvent(window, 'online'),
  fromEvent(window, 'offline')
).pipe(map(() => navigator.onLine))

Copy link

ghost commented Apr 24, 2020

Any samples for unit testing in angular, how do we trigger these events during testing.

Copy link

ghost commented Apr 24, 2020

@thecyberd3m0n did you manage to get unit testing for this

@FelixEhuan
Copy link

@kumar2live I don't know if you're still looking for a way to test this but you don't have to worry about online and offline behaviors, that's part of the browser, you only need to test your responses to different responses of that observable (i.e. Create a mock observable that emits true or false)

Copy link

ghost commented Sep 11, 2020

Thanks for responding, you are correct! I managed to use different RXJS events to handle this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment